Flutter中的动画介绍

标签: 编程学习 Flutter学习

动画的控制

使用 AnimationController 主要是对动画进行控制,包含的操作有启动forward()、停止stop() 、反向播放 reverse()等。 下面的代码就是创建一个控制器

AnimationController controller = AnimationController( vsync: this, duration: const Duration(milliseconds: 3000));

创建 AnimationController 的时候需要传递一个 vsync 参数,它接收一个 TickerProvider 类型的对象,它主要是创建一个通过 SchedulerBinding 来添加屏幕刷新回调的Ticker,这样每次屏幕刷新都会调用 TickerCallback,这样会防止屏幕外动画消耗不必要的资源,比如锁屏后屏幕会停止刷新。一般是在实现动画的类上进行 with TickerProviderStateMixin 操作。

动画的实现

使用 Animation 来实现动画,Animation 是一个抽象类,Animation 对象是一个在一段时间内依次生成一个区间(Tween)之间值的类。Animation 对象在整个动画执行过程中输出的值可以是线性的、曲线的、一个步进函数或者任何其他曲线函数等等。 我们可以通过 Animation 来监听动画每一帧以及执行状态的变化,由于 AnimationController 是 Animation 的派生类,所以 AnimationController 也可以调用

Animation().addListener()
Animation().addStatusListener()

CurvedAnimation 是 Animation 的子类,实现的是线性变换动画,比如 linear(匀速的)、decelerate(匀减速)、ease(开始加速,后面减速)、easeIn(开始慢,后面快)、easeOut(开始快,后面慢)、easeInOut(开始慢,然后加速,最后再减速)

CurvedAnimation curve = CurvedAnimation(parent: controller, curve: Curves.easeIn);

我们可以使用 Tween 生成不同的值来表示 UI 不同的动画值

Tween tween = Tween<double>(begin: -1.0, end: 1.0);
Tween color = ColorTween(begin: Colors.black12, end: Colors.black);

要使用Tween对象,需要调用其 animate() 方法,然后传入一个控制器对象

Animation moonRotationAnim = Tween<double>(begin: 0.0, end: 1.0,).animate(_moonFadeController);

做一个启动动画

这个启动动画包含一个旋转的月亮,一个移动的蓝色半圆还有一个灯光

class AnimationPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return _AnimationState();
  }
}

class _AnimationState extends State<AnimationPage> with TickerProviderStateMixin {
  ///月亮背景
  AnimationController _moonController;
  AnimationController _moonFadeController;
  AnimationController _moonRotationController;
  AnimationController _moonSlideController;
  Animation _moonRotationAnim;
  Animation _moonFadeAnimation;
  Animation _moonSlideAnimation;

  ///蓝色半圆背景
  AnimationController _semicircleFadeController;
  Animation _semicircleFadeAnimation;
  Animation _semicircleSlideAnimation;

  ///灯光背景
  AnimationController _lightController;
  Animation _lightFadeAnimation;
  Animation _lightSlideAnimation;

  @override
  void initState() {
    // TODO: implement initState
    super.initState();

    _initAnimation();
    _handlerInitAnimation();
  }

  ///记得销毁
  @override
  dispose() {
    _moonController.dispose();
    _moonFadeController.dispose();
    _moonRotationController.dispose();
    _moonSlideController.dispose();
    _semicircleFadeController.dispose();
    _lightController.dispose();
    super.dispose();
  }

  _handlerInitAnimation() {
    _moonController.addStatusListener((status) {
      if (status == AnimationStatus.forward) {
        print("动画开始");
      } else if (status == AnimationStatus.completed) {
        print("动画结束");
      }
    });
  }

  _initAnimation() {
    ///月亮背景
    _moonController = AnimationController(vsync: this, duration: Duration(milliseconds: 3000))
        ..addListener(() {
          if (_moonFadeController.isDismissed) {
            _moonFadeController.forward();
          }
          if (_moonRotationController.isDismissed) {
            _moonRotationController.forward();
          }
          if (_lightController.isDismissed) {
            _lightController.forward();
          }
          if (_semicircleFadeController.isDismissed && _moonController.value > 0.7) {
            _semicircleFadeController.forward();
          }
          if (_moonSlideController.isDismissed && _moonController.value > 0.8) {
            _moonSlideController.forward();
          }
        });

    _moonFadeController = AnimationController(vsync: this, duration: Duration(milliseconds: 500));
    _moonRotationController = AnimationController(vsync: this, duration: Duration(milliseconds: 3000));
    _moonSlideController = AnimationController(vsync: this, duration: Duration(milliseconds: 700));
    _moonFadeAnimation = Tween<double>(begin: 0.0, end: 1.0,).animate(_moonFadeController);
    _moonRotationAnim = Tween<double>(begin: 0, end: -0.125,).animate(_moonRotationController);
    _moonSlideAnimation = Tween<Offset>(begin: Offset.zero, end: const Offset(0.1, 0)).animate(_moonSlideController);

    ///蓝色半圆背景
    _semicircleFadeController = AnimationController(vsync: this, duration: Duration(milliseconds: 800));
    _semicircleSlideAnimation = Tween<Offset>(begin: Offset.zero, end: const Offset(-0.2, 0)).animate(_semicircleFadeController);
    _semicircleFadeAnimation = Tween<double>(begin: 0.0, end: 1.0,).animate(_semicircleFadeController);

    ///灯光背景
    _lightController = AnimationController(vsync: this, duration: Duration(milliseconds: 500));
    _lightFadeAnimation = Tween<double>(begin: 0.0, end: 1.0,).animate(_lightController);
    _lightSlideAnimation = Tween<Offset>(begin: Offset.zero, end: const Offset(0.4, 0)).animate(_lightController);
  }

  @override
  Widget build(BuildContext context) {
    ///启动动画
    _moonController.forward();

    double size = MediaQuery.of(context).size.width * 0.54;
    double margin = MediaQuery.of(context).size.width * 0.51;

    return Scaffold(
      backgroundColor: Color(0xff000000),
      body: Stack(
        children: <Widget>[
          ///背景半圆(透明度低)
          Container(
            alignment: Alignment.center,
            margin: EdgeInsets.only(bottom: margin),
            ///动画组件
            child: FadeTransition(
              ///控制 child 透明度的动画
              opacity: _semicircleFadeAnimation,
              ///动画组件
              child: SlideTransition(
                ///实现相对自身的位移
                position: _semicircleSlideAnimation,
                child: Image.asset(
                  'assets/images/splash_d_back.png',
                  width: size,
                  height: size,
                ),
              ),
            ),
          ),
          ///月亮
          Container(
            alignment: Alignment.center,
            margin: EdgeInsets.only(bottom: margin),
            ///透明度
            child: FadeTransition(
              ///位移
              child: SlideTransition(
                ///旋转
                child: RotationTransition(
                  child: Image.asset(
                    'assets/images/splash_moon.png',
                    width: size,
                    height: size,
                  ),
                  turns: _moonRotationAnim,
                ),
                position: _moonSlideAnimation,
              ),
              opacity: _moonFadeAnimation,
            ),
          ),
          ///背景半圆(透明度高)
          Container(
            alignment: Alignment.center,
            margin: EdgeInsets.only(bottom: margin),
            child: FadeTransition(
              child: SlideTransition(
                child: Image.asset(
                  'assets/images/splash_d_front.png',
                  width: size,
                  height: size,
                ),
                position: _semicircleSlideAnimation,
              ),
              opacity: _semicircleFadeAnimation,
            ),
          ),
          ///灯光
          Container(
            alignment: Alignment.topCenter,
            child: FadeTransition(
              child: SlideTransition(
                child: Image.asset(
                  'assets/images/splash_light.png',
                  scale: 3.0,
                ),
                position: _lightSlideAnimation,
              ),
              opacity: _lightFadeAnimation,
            ),
          ),
        ],
      ),
    );
  }
}

其他

当然 Flutter 中的动画还有其他的应用,比如路由动画、Hero 动画、动画组件等等,总的来说 Flutter 中的动画使用起来简单方便了许多,用到了可以看一下~