Flutter组合动画学习

如何使用动画控制器和动画来创建一个简单的动画效果。具体来说,它通过一个 `AnimationController` 来控制两个动画,一个用于旋转,一个用于绘制。

前置知识点学习

SingleTickerProviderStateMixin

`SingleTickerProviderStateMixin` 是 Flutter 中一个常用的混入(mixin),用于提供 `Ticker` 对象的简单实现。`Ticker` 是动画时间驱动的核心组件,能够在每一帧时调用回调方法。`SingleTickerProviderStateMixin` 通常用于需要一个 `AnimationController` 的 `State` 类中。

关键点

  • `Ticker`:它是一个计时器,在每一帧调用一个回调。用于驱动动画。
  • `AnimationController`:依赖于 `Ticker` 来更新动画的状态。`AnimationController` 需要一个 `TickerProvider` 来提供 `Ticker`。
  • `SingleTickerProviderStateMixin`:提供一个 `Ticker`,适用于仅需要一个 `Ticker` 的动画场景。

代码示例

以下是一个简单的例子,展示如何在 `State` 类中使用 `SingleTickerProviderStateMixin` 来创建一个动画:

Dart 复制代码
import 'package:flutter/material.dart';

class MyAnimatedWidget2 extends StatefulWidget {
  const MyAnimatedWidget2({super.key});

  @override
  _MyAnimatedPageState createState() {
    return _MyAnimatedPageState();
  }
}

class _MyAnimatedPageState extends State<MyAnimatedWidget2>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;

  @override
  void initState() {
    super.initState();
    // 初始化 AnimationController
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 2),
    );

    // 定义一个简单的补间动画(从 0 到 1)
    _animation = Tween<double>(begin: 0, end: 1).animate(_controller);

    // 启动动画
    _controller.forward();
  }

  @override
  void dispose() {
    // 释放资源
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Simple Animation"),
      ),
      body: Center(
        child: AnimatedBuilder(
          animation: _animation,
          builder: (context, child) {
            return Opacity(
              opacity: _animation.value,
              child: Container(
                width: 200,
                height: 200,
                color: Colors.blue,
              ),
            );
          },
        ),
      ),
    );
  }
}

解释

  • `with SingleTickerProviderStateMixin`: 这个混入使得 `_MyHomePageState` 类能够作为 `TickerProvider` 使用,提供给 `AnimationController` 使用。
  • `vsync: this`: 这里的 `vsync` 参数指定了 `TickerProvider`,通过 `SingleTickerProviderStateMixin`,`this` 就是当前的 `State`,因此可以直接使用。
  • `AnimationController`: 负责管理动画的状态和时间线。通过 `forward()`、`reverse()` 等方法来控制动画的播放。
  • `Tween` 和 `Animation`: `Tween` 定义了动画的值范围,而 `Animation` 是驱动这个值变化的实际对象。
  • `AnimatedBuilder`: 用于构建依赖于动画的 UI,每次动画状态改变时都会重新构建。

通过 `SingleTickerProviderStateMixin`,你可以轻松地在 Flutter 中实现简单的动画效果,而不必手动管理 `Ticker` 的生命周期。对于需要

总结

`SingleTickerProviderStateMixin` 是一个便捷的工具,用于实现需要单个 `Ticker` 的动画场景。

Opacity

在 Flutter 中,`Opacity` 是一个用于控制子组件透明度的控件。通过调整透明度,你可以使一个组件部分或完全透明。这在构建具有视觉层次和动态效果的用户界面时非常有用。

基本用法

`Opacity` 小部件接受一个 `opacity` 参数,该参数是一个 `double` 类型的值,范围从 0.0 到 1.0:

  • `0.0` 表示完全透明(不可见)。
  • `1.0` 表示完全不透明(可见)。

示例

Dart 复制代码
import 'package:flutter/material.dart';

class OpacityExample extends StatelessWidget {
  const OpacityExample({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Opacity Example'),
      ),
      body: Center(
        child: Opacity(
          opacity: 0.5,
          child: Container(
            width: 100,
            height: 100,
            color: Colors.blue,
          ),
        ),
      ),
    );
  }
}

关键点

1.性能考虑:`Opacity` 是一个相对简单的控件,但在某些情况下可能会影响性能,特别是当它包裹着一个复杂的子组件时。对于简单的颜色变化,使用 `Colors` 的 `withOpacity` 方法可能更高效。

2.动画效果:与 `AnimationController` 和 `AnimatedBuilder` 配合使用,可以创建平滑的透明度动画。例如,将 `Opacity` 结合 `Tween` 和 `Animation` 来实现淡入淡出效果。

3.子组件属性:`Opacity` 影响其子组件的可见性,但它不会改变子组件的布局特性。即使完全透明,子组件仍然占据布局空间。

4.替代方法:在某些情况下,`FadeTransition` 可能是更好的选择,特别是在需要动画时。`FadeTransition` 专门用于处理透明度动画,并直接与 `Animation` 对象集成。

使用场景

  • 视觉效果:在创建具有层次的 UI 时,使用透明度来突出显示或淡化特定元素。
  • 动画:在创建淡入淡出效果时,使用 `Opacity` 结合动画控制器。
  • 动态 UI:在响应用户交互时,通过透明度变化来反馈状态变化。

通过灵活运用 `Opacity`,你可以在 Flutter 应用中创建丰富且动态的视觉效果。

RotationTransition

`RotationTransition` 是 Flutter 中的一个动画小部件,用于在一段时间内对其子组件应用旋转动画。它是构建动画的一种便捷方式,特别适合需要对组件进行旋转效果的场景。

主要属性

  • `turns`: 这是一个 `Animation` 类型的属性,定义了旋转的角度。角度是以圈(revolution)为单位的,比如 0.25 表示旋转 90 度(即四分之一圈),1.0 表示旋转 360 度(即一整圈)。
  • `child`: 需要旋转的子组件。`RotationTransition` 将对这个组件施加旋转效果。

使用方法

`RotationTransition` 通常与 `AnimationController` 和 `Tween` 一起使用。`AnimationController` 用于控制动画的时长和播放状态,而 `Tween` 用于定义动画的起始和结束值。

示例

以下是一个简单的示例,展示如何使用 `RotationTransition` 实现一个简单的旋转动画:

Dart 复制代码
import 'package:flutter/material.dart';

class RotationTransitionExample extends StatefulWidget {
  const RotationTransitionExample({super.key});

  @override
  _RotationTransitionExampleState createState() {
    return _RotationTransitionExampleState();
  }
}

class _RotationTransitionExampleState extends State<RotationTransitionExample>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 2),
    )..repeat();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('RotationTransition Example'),
      ),
      body: Center(
        child: RotationTransition(
          turns: _controller,
          child: Container(
            width: 100.0,
            height: 100.0,
            color: Colors.blue,
          ),
        ),
      ),
    );
  }
}

解释

  • `AnimationController`: 控制动画的时长和播放方式。在 `initState` 中初始化,并设置为循环播放。
  • `RotationTransition`: 使用 `AnimationController` 的值作为 `turns` 属性。这个值从 0.0 到 1.0 不断变化,实现旋转效果。
  • `child`: 被旋转的组件,在这个例子中是一个蓝色的 `Container`。

使用场景

  • 旋转图标或按钮:可以用来制作旋转加载指示器、旋转按钮等。
  • 动态效果:在用户交互时,通过旋转来提供视觉反馈。
  • 动画过渡:在组件状态变化时,使用旋转动画增强用户体验。

通过使用 `RotationTransition`,你可以轻松地在 Flutter 应用中实现旋转动画效果,增强应用的动态交互体验。

Tween

在 Flutter 中,`Tween` 是动画框架中一个核心组件,用于定义从一个值到另一个值的插值(interpolation)。它提供了一种简单的方式来指定动画的起始值和结束值,并在动画过程中计算这些值之间的中间值。

主要功能

`Tween` 的主要功能是生成一系列的值,这些值在动画的生命周期内从起始值逐渐变化到结束值。这对于创建平滑的动画效果非常重要。

基本属性

  • `begin`: 动画的起始值。
  • `end`: 动画的结束值。

工作原理

  • `Tween` 通过一个 `Animation` 对象(通常是 `Animation`)来驱动,其 `value` 属性在 0.0 到 1.0 之间变化。
  • `Tween` 的 `lerp(double t)` 方法用于计算动画的当前值,其中 `t` 是 `Animation` 的当前进度。

常见使用场景

1.简单的数值动画: 使用 `Tween` 在两个数值之间插值。

2.颜色动画: 使用 `ColorTween` 在两种颜色之间过渡。

3.尺寸和位置动画: 使用 `SizeTween` 或 `RectTween` 在不同的尺寸或位置之间插值。

示例代码

以下是一个简单的例子,展示如何使用 `Tween` 和 `AnimationController` 创建一个从 0 到 300 的动画:

Dart 复制代码
import 'package:flutter/material.dart';

class TweenExample extends StatefulWidget {
  const TweenExample({super.key});

  @override
  _TweenExampleState createState() {
    return _TweenExampleState();
  }
}

class _TweenExampleState extends State<TweenExample>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this,
    );
    // 定义一个 Tween 从 0 到 300
    _animation = Tween<double>(begin: 0, end: 300).animate(_controller)
      ..addListener(() {
        setState(() {});
      });
    // 启动动画
    _controller.forward();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Tween Example'),
      ),
      body: Center(
        child: Container(
          width: _animation.value,
          height: _animation.value,
          color: Colors.blue,
        ),
      ),
    );
  }
}

解释

  • `AnimationController`: 控制动画的时长和进度。
  • `Tween(begin: 0, end: 300)`: 定义了一个从 0 到 300 的插值。
  • `animate(_controller)`: 将 `Tween` 连接到 `AnimationController`,以便在动画进度更改时计算当前值。
  • `addListener`: 每当动画的值改变时,重新构建 UI。

Paint

在 Flutter 中,`Paint` 是一个用于配置绘图操作的类。它包含了关于如何绘制图形、文本和图像的详细信息。`Paint` 可以用来指定颜色、样式、阴影、混合模式等属性,是自定义绘制的核心工具之一。

基本属性

`Paint` 有许多属性可以配置绘图行为,以下是一些常用的属性:

  • `color`: 设置绘制内容的颜色。
  • `style`: 定义绘制的风格,可以是 `PaintingStyle.fill`(填充)或 `PaintingStyle.stroke`(描边)。
  • `strokeWidth`: 描边的宽度,仅在 `style` 为 `stroke` 时有效。
  • `blendMode`: 定义颜色如何与现有的绘制内容混合。
  • `shader`: 用于渐变或复杂的着色效果。
  • `maskFilter`: 用于模糊和其他效果。
  • `filterQuality`: 定义图片的质量(如在缩放时)。
  • `isAntiAlias`: 是否对绘制进行抗锯齿处理。
  • `strokeCap`: 描边的末端形状,可以是 `StrokeCap.round`、`StrokeCap.butt`、或 `StrokeCap.square`。
  • `strokeJoin`: 描边的连接方式,可以是 `StrokeJoin.miter`、`StrokeJoin.round`、或 `StrokeJoin.bevel`。

使用场景

`Paint` 通常与 `Canvas` 结合使用,通过 `CustomPainter` 来实现自定义绘制。`CustomPainter` 提供了两个主要方法:`paint(Canvas, Size)` 和 `shouldRepaint(CustomPainter oldDelegate)`。

代码示例

Dart 复制代码
import 'package:flutter/material.dart';
class CirclePainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.blue
      ..style = PaintingStyle.fill; // 濉厖鏍峰紡
    final center = Offset(size.width / 2, size.height / 2);
    final radius = size.width / 4;
    canvas.drawCircle(center, radius, paint);
  }
  @override
  bool shouldRepaint(CustomPainter oldDelegate) => false;
}
class PaintExample extends StatelessWidget {
  const PaintExample({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Paint Example'),
      ),
      body: Center(
        child: CustomPaint(
          size: const Size(200, 200),
          painter: CirclePainter(),
        ),
      ),
    );
  }
}

解释

  • `CustomPainter`: 一个抽象类,用于自定义绘制。通过实现 `paint` 方法来定义绘制逻辑。
  • `Canvas`: 提供了用于绘制的基本操作,比如 `drawCircle`、`drawRect`、`drawPath` 等。
  • `Paint`: 配置绘制操作的细节,比如颜色和样式。
  • `CustomPaint`: 一个小部件,用于在 Flutter UI 中展示自定义绘制的内容。

CustomPaint

`CustomPaint` 是 Flutter 中的一个小部件,用于在屏幕上绘制自定义图形。通过结合 `CustomPainter` 类,`CustomPaint` 可以实现复杂的绘制逻辑。

主要组成部分

1.`CustomPainter`: 一个抽象类,你需要继承并实现它的 `paint` 方法来定义绘制逻辑。`CustomPainter` 是 `CustomPaint` 的核心部分。

2.`CustomPaint` 小部件: 它包含一个 `painter` 属性,该属性接收一个 `CustomPainter`

属性

  • `painter`: 一个 `CustomPainter` 对象,负责绘制主要内容。
  • `foregroundPainter`: 类似于 `painter`,但绘制在子组件的前景(在子组件上面)。
  • `child`: 可选的子组件,当需要在自定义绘制的背景或前景上叠加组件时使用。
  • `size`: 指定 `CustomPaint` 的大小。如果未设置,将会使用子组件的大小。

示例

以下是一个使用 `CustomPaint` 绘制简单图形的示例:

Dart 复制代码
import 'package:flutter/material.dart';

class MyPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.blue
      ..style = PaintingStyle.fill;
    // 绘制一个圆形
    final circleCenter = Offset(size.width / 2, size.height / 2);
    final circleRadius = size.width / 4;
    canvas.drawCircle(circleCenter, circleRadius, paint);
    // 绘制一个矩形
    final rect = Rect.fromLTWH(50, 50, size.width - 100, size.height - 100);
    paint.color = Colors.red;
    canvas.drawRect(rect, paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => false;
}

class CustomPaintExample extends StatelessWidget {
  const CustomPaintExample({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('CustomPaint Example'),
      ),
      body: Center(
        child: CustomPaint(
          size: const Size(200, 200),
          painter: MyPainter(),
        ),
      ),
    );
  }
}

组合动画代码学习

Dart 复制代码
import 'package:flutter/material.dart';

class MyAnimaDemoPage extends StatefulWidget {
  const MyAnimaDemoPage({super.key});

  @override
  _MyAnimaDemoPageState createState() {
    return _MyAnimaDemoPageState();
  }
}

class _MyAnimaDemoPageState extends State<MyAnimaDemoPage>
    with SingleTickerProviderStateMixin {
  late AnimationController controller1;

  late Animation animation2;

  Animation? animation1;

  @override
  void initState() {
    super.initState();
    controller1 =
        AnimationController(vsync: this, duration: const Duration(seconds: 3));

    animation1 = Tween(begin: 0.0, end: 200.0).animate(controller1)
      ..addListener(() {
        setState(() {});
      });

    animation2 = Tween(begin: 0.0, end: 1.0).animate(controller1);

    controller1.repeat();
  }

  @override
  void dispose() {
    controller1.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("AnimaDemoPage"),),
      body: RotationTransition(
        turns: animation2 as Animation<double>,
        child: Center(
          child: Container(
            height: 200,
            width: 200,
            color: Colors.blue,
            child: CustomPaint(
              foregroundPainter: _MyAnimationPainter(animation1),
            ),
          ),
        ),
      ),
    );
  }
}


class _MyAnimationPainter extends CustomPainter {

  final Paint _paint = Paint();

  Animation? animation;

  _MyAnimationPainter(this.animation);

  @override
  void paint(Canvas canvas, Size size) {
    _paint
      ..color = Colors.redAccent
      ..strokeWidth = 4
      ..style = PaintingStyle.stroke;

    canvas.drawCircle(const Offset(100, 100), animation!.value * 1.5, _paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return true;
  }

}
相关推荐
且听真言1 个月前
Flutter实现气泡提示框学习
path·自定义view·custompainter·rect·arrowlocation
gis分享者1 个月前
学习threejs,使用TWEEN插件实现动画
threejs·tween·补间动画
欣慰的三叶草(● ̄(エ) ̄●)2 个月前
【An】Animate 2024 for【Mac】 An动画设计制作软件 安装教程——保姆级教程
macos·mac软件·animate·an2024·an·动画设计制作软件·an动画设计
Mac分享吧2 个月前
【An】Animate 2024 for【Mac】 An动画设计制作软件 安装教程——保姆级教程
macos·软件需求·animate·an·动画设计·动画设计软件
Forever不止如此3 个月前
【CustomPainter】绘制圆环
flutter·custompainter·圆环
Kbattery7 个月前
Android11重复事件上报流程
android·input·事件分发·repeat·输入系统
猴叻鳢10 个月前
Flutter中动画的实现
flutter·动画·tween
唐诺1 年前
Android 获取屏幕方向,根据屏幕旋转角度判断屏幕实际方向
android·display·windowmanager·rotation
暴怒的代码1 年前
Vue3的transition标签以及animate.css使用详解
前端·css·vue3·animate·transition·gasp