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(),
          ),
        ),
      ),
    );
  }
}
相关推荐
WDeLiang11 小时前
Flutter - UIKit开发相关指南 - 导航
flutter·ios·dart
程序猿阿伟16 小时前
《Flutter社交应用暗黑奥秘:模式适配与色彩的艺术》
前端·flutter
融云1 天前
集成指南:如何采用融云 Flutter IMKit 实现双端丝滑社交体验
flutter
EndingCoder1 天前
跨平台移动开发框架React Native和Flutter性能对比
flutter·react native·react.js
Double Point1 天前
`RotationTransition` 是 Flutter 中的一个动画组件,用于实现旋转动画效果
flutter
亚洲小炫风1 天前
flutter 项目工程文件夹组织结构
flutter·flutter工程结构
Double Point1 天前
Flutter 中 vsync
flutter
Double Point2 天前
ScaleTransition 是 Flutter 中的一个动画组件,用于实现缩放动画效果。
flutter
saxihuangxing2 天前
flutter build apk出现的一些奇怪的编译错误
flutter
恋猫de小郭3 天前
Flutter 合并 ‘dot-shorthands‘ 语法糖,Dart 开始支持交叉编译
android·flutter·ios