一统天下 flutter - 动画: Animation - 动画基础(以直线型动画为例)

源码 https://github.com/webabcd/flutter_demo
作者 webabcd

一统天下 flutter - 动画: Animation - 动画基础(以直线型动画为例)

示例如下:

lib\animation\animation.dart

/*
 * Animation - 动画基础(以直线型动画为例)
 *
 * Animation<T> 用于将 T 动画化,它知道动画的状态,以及 T 的值,但是与 UI 无关
 * AnimationController 继承自 Animation<double>,其增加了一些管理 Animation<double> 的功能
 *   默认会在 0.0 到 1.0 之间做动画(直线型)
 *   可以操作动画,比如前进,倒退,重复,停止等
 *
 * 注:在 flutter 中玩动画,AnimationController 是必不可少的
 */

import 'package:flutter/material.dart';
import 'package:flutter_demo/helper.dart';

class AnimationDemo extends StatefulWidget {
  const AnimationDemo({Key? key}) : super(key: key);

  @override
  _AnimationDemoState createState() => _AnimationDemoState();
}

class _AnimationDemoState extends State<AnimationDemo> with SingleTickerProviderStateMixin {

  late AnimationController _controller;

  String message = "";

  @override
  void initState() {
    super.initState();

    _controller = AnimationController(
      /// vsync 用于防止动画不在当前屏幕显示时消耗不必要的资源,需要 with SingleTickerProviderStateMixin
      ///   他会将动画定时器绑定到 Widget,当 Widget 不显示时,动画定时器就会暂停,当 Widget 显示时,动画定时器就会恢复
      vsync: this,
      /// 正向动画的时长
      duration: const Duration(seconds: 3),
      /// 反向动画的时长
      reverseDuration: const Duration(seconds: 1),
      /// 动画 double 的最小值(默认 0.0)
      lowerBound: 0.0,
      /// 动画 double 的最大值(默认 1.0)
      upperBound: 300.0
    )
      /// 动画值发生变化时触发的事件
      ..addListener(() {
        /// 获取当前的动画值
        log("value: ${_controller.value}");
        /// 重绘 Widget 从而在 UI 上实现动画
        setState(() {
          /// 获取当前的动画状态和动画值
          message = "isAnimating:${_controller.isAnimating}\n"
              "isCompleted:${_controller.isCompleted}\n"
              "isDismissed:${_controller.isDismissed}\n"
              "status:${_controller.status}\n"
              "value:${_controller.value}";
        });
      })
      /// 动画状态发生变化时触发的事件
      ..addStatusListener((status) {
        /// AnimationStatus.forward - 正向动画进行中
        /// AnimationStatus.reverse - 反向动画进行中
        /// AnimationStatus.completed - 正向动画完成
        /// AnimationStatus.dismissed - 反向动画完成(动画的元素回到了起始位置)
        log("status: $status");
      });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.orange,
      child: Column(
        children: [
          Flexible(
            child: Center(
              child: Container(
                color: Colors.blue,
                height: _controller.value,  /// 从 Animation<T> 中获取当前的动画值
                width: _controller.value,   /// 从 Animation<T> 中获取当前的动画值
              ),
            ),
          ),
          Wrap(
            children: [
              ElevatedButton(
                child: const Text('forward'),
                onPressed: () {
                  /// 启动正向动画(动画的时长就是 AnimationController 中的 duration 的值)
                  /// 注:forward(), reverse(), repeat() 返回的是一个 TickerFuture 对象
                  var tickerFuture = _controller.forward();
                },
              ),
              ElevatedButton(
                child: const Text('reverse'),
                onPressed: () {
                  /// 启动反向动画(动画的时长就是 AnimationController 中的 reverseDuration 的值)
                  _controller.reverse();
                },
              ),
              ElevatedButton(
                child: const Text('repeat'),
                onPressed: () {
                  /// 启动循环动画(其中的正向动画部分和反向动画部分的时长均是 AnimationController 中的 duration 的值)
                  _controller.repeat(reverse: true);
                },
              ),
              ElevatedButton(
                child: const Text('reset'),
                onPressed: () {
                  /// 复位
                  _controller.reset();
                },
              ),
              ElevatedButton(
                child: const Text('stop'),
                onPressed: () {
                  /// 停止动画
                  _controller.stop();
                },
              ),
              ElevatedButton(
                child: const Text('animateTo()'),
                onPressed: () {
                  /// 通过 animateTo() 启动动画(从当前值动画到目标值),目标值必须在 lowerBound 和 upperBound 之间
                  /// 下面的例子会启动动画,_controller 会从当前值动画到 120,时长 1 秒,缓动 Curves.ease
                  _controller.animateTo(120, duration: const Duration(seconds: 1), curve: Curves.ease);
                },
              ),
            ],
          ),
        ],
      ),
    );
  }

  @override
  void dispose() {
    /// 清理 AnimationController
    _controller.dispose();
    super.dispose();
  }
}

源码 https://github.com/webabcd/flutter_demo
作者 webabcd

posted @ 2023-03-22 11:21  webabcd  阅读(74)  评论(0编辑  收藏  举报