Flutter 动画之 Explicit 显式动画

Flutter 动画之 Explicit 显式动画

  • Explicit 显式动画指的是通过手动配置和控制动画过程来实现动画效果的方式,提供对动画状态(比如正向播放、反向播放和重复播放等)的精细化管理,与隐式动画(由 Flutter 自动管理动画过程)相对应
  • 显式动画的核心在于使用 AnimationController 和 Animation
  • 显式动画可以精细控制,灵活性较高

AnimationController

  • AnimationController 继承自 Animation,动画控制器,控制着动画的播放、暂停等状态,管理动画的 duration 持续时间和 vsync(TickerProvider)参数
  • 可以监听动画的状态变化(比如如是否完成、是否前进或后退等)

Animation

  • Animation 是一个抽象类,代表动画的值随时间的变化,比如通过 Tween#animate 方法绑定到 AnimationController 生成 Animation
  • Tween 子类支持颜色、尺寸和区域等多种类型(比如 ColorTween、SizeTween 和 RectTween)
  • Tween 定义了动画的 begin 起始值和 end 结束值(比如 0.0 -> 1.0),Tween 补间由系统自动生成中间值

使用 addListener 和 setState 的方式

  • 1 初始化动画控制器:在 State 对象的 initState 方法中创建 AnimationController 实例,并指定动画的 duration 持续时间和 vsync(TickerProvider)参数,记得在 dispose 方法中进行释放
  • 2 定义动画值的变化范围:使用 Tween 等类定义动画值的起始值和结束值(比如使用 Tween 定义一个从 0.0 到 1.0 的变化范围)
  • 3 监听动画值的变化:通过 Animation#addListener 方法添加监听器,在监听器中调用 setState 方法来触发 UI 界面重绘,从而更新界面以反映动画元素的位置、大小等属性的改变
  • 4 启动和控制动画:调用 AnimationController 的 forward、reverse 或 repeat 等方法来启动正向播放、反向播放或循环播放
dart 复制代码
class ExplicitAnimationWidget extends StatefulWidget {
  const ExplicitAnimationWidget({super.key});

  @override
  State<ExplicitAnimationWidget> createState() =>
      _ExplicitAnimationWidgetState();
}

//SingleTickerProviderStateMixin 实现了 TickerProvider 抽象类,通过混入让 State 成为一个 TickerProvider
class _ExplicitAnimationWidgetState extends State<ExplicitAnimationWidget>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;

  @override
  void initState() {
    super.initState();
    //1 初始化动画控制器
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this, //TickerProvider,将 State 传入
    );
    //2 定义动画值的变化范围
    //Animation<Color?> _colorAnimation = ColorTween(begin: Colors.red, end: Colors.green).animate(_controller);
    _animation = Tween<double>(begin: 50.0, end: 200.0).animate(_controller);

    //3 监听动画值的变化
    _animation.addListener(() {
      setState(() {}); //触发 UI 更新
    });
    _animation.addStatusListener((status) {
      //监听状态变化
      //if (_controller.isCompleted) {
      if (status == AnimationStatus.completed) {
        //动画完成时触发
        _controller.reverse(); //反向播放
      }
    });
    
    _startAnimation();
  }

  //4 启动和控制动画
  void _startAnimation() {
    _controller.forward(); //正向播放
    //_controller.repeat(); //循环播放
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('显式动画示例'),
      ),
      body: Center(
        child: SizedBox(
          width: _animation.value, //动画元素的属性改变
          height: _animation.value, //动画元素的属性改变
          child: const FlutterLogo(),
        ),
      ),
    );
  }
}

使用 AnimatedWidget 组件

  • 其实 AnimatedWidget 内部就是封装 addListener 和 setState 的方式,相当于使用 AnimatedWidget 可以省略监听的逻辑(无需手动调用 addListener 和 setState),将动画逻辑与 UI 组件解耦,方便复用动画
  • 1 初始化动画控制器:在 State 对象的 initState 方法中创建 AnimationController 实例,并指定动画的 duration 持续时间和 vsync(TickerProvider)参数,记得在 dispose 方法中进行释放
  • 2 定义动画值的变化范围:使用 Tween 等类定义动画值的起始值和结束值(比如使用 Tween 定义一个从 0.0 到 1.0 的变化范围)
  • 3 启动和控制动画:调用 AnimationController 的 forward、reverse 或 repeat 等方法来启动正向播放、反向播放或循环播放
dart 复制代码
class MyAnimatedWidget extends StatefulWidget {
  const MyAnimatedWidget({super.key});

  @override
  State<MyAnimatedWidget> createState() => _MyAnimatedWidgetState();
}

//SingleTickerProviderStateMixin 实现了 TickerProvider 抽象类,通过混入让 State 成为一个 TickerProvider
class _MyAnimatedWidgetState extends State<MyAnimatedWidget>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;

  @override
  void initState() {
    super.initState();
    //1 初始化动画控制器
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this, //TickerProvider,将 State 传入
    );
    //2 定义动画值的变化范围
    //Animation<Color?> _colorAnimation = ColorTween(begin: Colors.red, end: Colors.green).animate(_controller);
    _animation = Tween<double>(begin: 50.0, end: 200.0).animate(_controller);

    _animation.addStatusListener((status) {
      //监听状态变化
      //if (_controller.isCompleted) {
      if (status == AnimationStatus.completed) {
        //动画完成时触发
        _controller.reverse(); //反向播放
      }
    });

    _startAnimation();
  }

  //3 启动和控制动画
  void _startAnimation() {
    _controller.forward(); //正向播放
    //_controller.repeat(); //循环播放
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('AnimatedWidget 示例'),
      ),
      body: Center(
        child: CustomAnimatedWidget(animation: _animation),
      ),
    );
  }
}

//自定义 AnimatedWidget
class CustomAnimatedWidget extends AnimatedWidget {
  const CustomAnimatedWidget({super.key, required Animation<double> animation})
      : super(listenable: animation);

  @override
  Widget build(BuildContext context) {
    final animation = listenable as Animation<double>;
    return SizedBox(
      width: animation.value, //动画元素的属性改变
      height: animation.value, //动画元素的属性改变
      child: const FlutterLogo(),
    );
  }
}

使用以 Transition 结尾的组件

  • 系统内置的显式动画
  • 1 初始化动画控制器:在 State 对象的 initState 方法中创建 AnimationController 实例,并指定动画的 duration 持续时间和 vsync(TickerProvider)参数,记得在 dispose 方法中进行释放
  • 2 定义动画值的变化范围:使用 Tween 等类定义动画值的起始值和结束值(比如使用 Tween 定义一个从 0.0 到 1.0 的变化范围)
  • 3 启动和控制动画:调用 AnimationController 的 forward、reverse 或 repeat 等方法来启动正向播放、反向播放或循环播放
dart 复制代码
//SlideTransition 继承自 AnimatedWidget
//ScaleTransition 继承自 MatrixTransition,而 MatrixTransition 又继承自 AnimatedWidget
//RotationTransition 继承自 MatrixTransition,而 MatrixTransition 又继承自 AnimatedWidget
//FadeTransition 继承自 SingleChildRenderObjectWidget,而 SingleChildRenderObjectWidget 又继承自 RenderObjectWidget
//
//平移动画,通过 position 控制位置
SlideTransition
//缩放动画,通过 scale 控制缩放
ScaleTransition
//旋转动画,通过 turns 控制旋转次数
RotationTransition
//透明度动画(比如实现淡入淡出效果),通过 opacity 控制不透明度
FadeTransition
//...
dart 复制代码
//SingleTickerProviderStateMixin 实现了 TickerProvider 抽象类,通过混入让 State 成为一个 TickerProvider
class _ScaleTransitionWidgetState extends State<ScaleTransitionWidget>
    with SingleTickerProviderStateMixin {
  late AnimationController _controller;
  late Animation<double> _animation;

  @override
  void initState() {
    super.initState();
    //1 初始化动画控制器
    _controller = AnimationController(
      duration: const Duration(seconds: 2),
      vsync: this, //TickerProvider,将 State 传入
    );
    //2 定义动画值的变化范围
    _animation = Tween<double>(begin: 0.4, end: 1.0).animate(_controller);

    _animation.addStatusListener((status) {
      //监听状态变化
      //if (_controller.isCompleted) {
      if (status == AnimationStatus.completed) {
        //动画完成时触发
        _controller.reverse(); //反向播放
      }
    });

    _startAnimation();
  }

  //3 启动和控制动画
  void _startAnimation() {
    _controller.forward(); //正向播放
    //_controller.repeat(); //循环播放
  }

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('ScaleTransition 示例'),
      ),
      body: Center(
        child: ScaleTransition(
          scale: _animation,
          child: const SizedBox(
            width: 100,
            height: 100,
            child: FlutterLogo(),
          ),
        ),
      ),
    );
  }
}
相关推荐
早起的年轻人2 小时前
Flutter BigInt 是用于处理任意精度整数的特殊数字类型,专为解决超大整数运算需求而设计
flutter
leluckys2 小时前
flutter 专题 六十六 Flutter Dio包网络请求抓包解决方案
flutter
爱吃鱼的锅包肉2 小时前
Flutter路由模块化管理方案
前端·javascript·flutter
李新_5 小时前
我们封装了哪些好用的Flutter Mixin
android·flutter
leluckys5 小时前
flutter 专题 六十三 Flutter入门与实战作者:xiangzhihong8Fluter 应用调试
前端·javascript·flutter
又菜又爱coding5 小时前
Flutter异常Couldn‘t find dynamic library in default locations
flutter
帅次5 小时前
Flutter Expanded 与 Flexible 详解
android·flutter·ios·小程序·webview
衿璃10 小时前
flutter 路由跳转动画设置
android·flutter
Nicholas6810 小时前
SchedulerBinding源码解析
flutter