美文网首页
五、Flutter之动画

五、Flutter之动画

作者: 夏_Leon | 来源:发表于2019-02-27 14:56 被阅读0次

主要参考:https://flutterchina.club/animations/ ,这里有很系统的讲解,要深入理解flutter的动画,务必顺着教程,从Animation、AnimationController、Tween、动画监听等看下来。

我们直接从封装比较方便的AnimatedWidget开始学习demo快速上手:

1、线性变化

//放大动画的封装组件
class Animation1 extends StatefulWidget {
  _Animation1State createState() => new _Animation1State();
}

class _Animation1State extends State<Animation1>
    with SingleTickerProviderStateMixin {
  AnimationController controller; //动画控制器,设置动画运行时间和值的计算规则
  Animation<double> animation; //动画值,须传递给动画图标,动画之所以动就是因为该值在变化

  initState() {
    super.initState();
    //必须传入动画时间和vsync,存在vsync时会防止屏幕外动画消耗不必要的资源
    controller = new AnimationController(
        duration: const Duration(milliseconds: 2000), vsync: this);
    //animation值取0~300之间,通过Tween来映射生成
    animation = new Tween(begin: 0.0, end: 300.0).animate(controller);
    //启动动画
    controller.forward();
  }

  Widget build(BuildContext context) {
    //把动画值传入动画图标EnlargeLogo,当动画启动后,该图标就会根据动画值的变化而变化
    return new EnlargeLogo(animation: animation);
  }

  dispose() {
    //组件销毁时记得销毁动画
    controller.dispose();
    super.dispose();
  }
}

//放大动画图标,本质就是一张图片,通过动画控制器修改height和width属性来达到放大的动画
class EnlargeLogo extends AnimatedWidget {
  EnlargeLogo({Key key, Animation<double> animation})
      : super(key: key, listenable: animation);

  Widget build(BuildContext context) {
    //传入的动画值
    final Animation<double> animation = listenable;

    return new Center(
      child: new Container(
        margin: new EdgeInsets.symmetric(vertical: 10.0),
        height: animation.value,
        width: animation.value,
        child: new FlutterLogo(), //FlutterLogo
      ),
    );
  }
}

上面这段代码实现了一个图标在2s内逐步放大的过程,重要代码都有注释。初学阶段我们从最底层的动画实现开始,自己去分解、实现动画。

动画分解开来就是一个图形的坐标值、颜色、透明度等在变化,如demo是一个放大动画,就是图标的height、width属性在变大,那我们就可以把动画分解成两步:
1、长宽值在指定时间内按规律地增大,这里不涉及任何UI,就是单纯的数值增大;
2、把这个值应用到图标的height、width上,值变化的时候图标就跟随变化(这里的图标必然是个StatefulWidget了)。

以上面的demo为例,Animation<double> animation 就是逐渐增大的值,它还可以是其他格式像Animation<Color>等,我们要把它传给图标EnlargeLogo,设为图标的长宽值。
AnimationController controller 是动画控制器,是一个特殊的Animation对象,在指定Duration中线性生成01.0的值,也可以手动设置lowerBound和upperBound,比如设为00.5。
new Tween(begin: 0.0, end: 300.0).animate(controller),Tween也可以设置计算边界begin和end,并把这种变化规律映射给Animation。

2、监听animation值及状态

更进一步的,我们可以对animation值进行监听,只要值发生变化就调用;也可以对status进行监听,在动画结束后反转动画,在反转结束后再播放放大动画。

animation = new Tween(begin: 0.0, end: 300.0).animate(controller)
      //..是级联符号,用上个表达式的返回值继续调用
      //添加对animation值的监听
      ..addListener(() {
        print(animation.value);
      })
      //添加状态监听放大结束后反转,缩小结束后正放。
      ..addStatusListener((status) {
        print(status);
        if (status == AnimationStatus.completed) {
          controller.reverse(); //翻转动画
        } else if (status == AnimationStatus.dismissed) {
          controller.forward(); //翻转动画
        }
      });

3、实现非线性的变化

CurvedAnimation类可以将动画过程定义为一个非线性曲线,Curves.fastOutSlowIn属性表示曲线为快速开始慢速结束的,使用如下:

   //非线性曲线
    CurvedAnimation curve =
    new CurvedAnimation(parent: controller, curve: Curves.fastOutSlowIn);

    //animation值取0~300之间,通过Tween来映射生成
    animation = new Tween(begin: 0.0, end: 300.0).animate(curve)

就在controller外再包一层变为非线性的,把CurvedAnimation映射给animation就行。动画的启动翻转等还是通过controller来操作。

4、AnimatedBuilder

教程中还有AnimatedBuilder重构,为什么要用AnimatedBuilder呢?按我的理解就是进一步解耦,把动画(单纯指动作)和组件(例子中的logo图标)分离开来,让动画可以方便复用在其他组件上。

AnimatedBuilder是继承自AnimatedWidget,原代码中的EnlargeLogo也是AnimatedWidget,所以AnimatedBuilder其实就是重构替代了AnimatedWidget,把class EnlargeLogo代码块替换为如下代码即可,其他像animation、controller的计算、启动都无需修改,就完成了AnimatedBuilder的重构。

//固定的图标组件,不在组件内设置宽高等
class SecondLogo extends StatelessWidget {
  Widget build(BuildContext context) {
    return Container(
      //图标充满父组件
      width: MediaQuery.of(context).size.width,
      height: MediaQuery.of(context).size.height,
      child: FlutterLogo(), //FlutterLogo
    );
  }
}

//放大动画,把需要进行动画的组件传入child,专注于动画过程,与图标组件解耦,返回的是已经套用过动画的组件
class EnlargeLogo extends StatelessWidget {
  EnlargeLogo2({this.child, this.animation});

  final Widget child; //需要进行动画的组件
  final Animation<double> animation;

  Widget build(BuildContext context) {
    return new Center(
      child: new AnimatedBuilder(
          animation: animation,
          builder: (BuildContext context, Widget child) {
            return new Container(
              height: animation.value,
              width: animation.value,
              child: child,
            );
          },
          child: child),
    );
  }
}

仔细看AnimatedBuilder的源码,其实就是一个内置了animation的AnimatedWidget,和我们一开始的实现过程很像,反而在图标组件外多套一层Builder,除非项目中有大量复用该动画的场景,否则没必要使用AnimatedBuilder,用AnimatedWidget更灵活容易理解。

5、并行动画

一般来说并行动画就是给它设置两套动画就行,但是AnimatedWidget的构造函数只接受一个Animation,那我们就只能在AnimatedWidget内部,去定义两套Tween,用不同的规则把同个Animation映射给对应的属性赋值。

//并行动画的父组件
class Animation2 extends StatefulWidget {
  _Animation2State createState() => new _Animation2State();
}

class _Animation2State extends State<Animation2> with TickerProviderStateMixin {
  AnimationController controller;
  Animation<double> animation;

  initState() {
    super.initState();
    controller = new AnimationController(
        duration: const Duration(milliseconds: 2000), vsync: this);
    animation = new CurvedAnimation(parent: controller, curve: Curves.bounceOut);

    //实现动画循环播放
    animation.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        controller.reverse();
      } else if (status == AnimationStatus.dismissed) {
        controller.forward();
      }
    });

    controller.forward();
  }

  Widget build(BuildContext context) {
    return new TwoAnimationWidget(animation: animation);
  }

  dispose() {
    controller.dispose();
    super.dispose();
  }
}

//两个并行动画组件,Tween的绑定从父组件挪到子组件中,利用Tween.evaluate,设置不同的Tween把同个animation映射给不同属性
class TwoAnimationWidget extends AnimatedWidget {

  //通过opacityAnimation.value来获取不透明度
  static final _opacityTween = new Tween<double>(begin: 0.1, end: 1.0);
  //通过sizeAnimation.value来获取大小
  static final _sizeTween = new Tween<double>(begin: 0.0, end: 300.0);

  TwoAnimationWidget({Key key, Animation<double> animation})
      : super(key: key, listenable: animation);

  Widget build(BuildContext context) {
    final Animation<double> animation = listenable;
    return new Center(
      child: new Opacity(
        opacity: _opacityTween.evaluate(animation),
        child: new Container(
          margin: new EdgeInsets.symmetric(vertical: 10.0),
          height: _sizeTween.evaluate(animation),
          width: _sizeTween.evaluate(animation),
          child: new FlutterLogo(),
        ),
      ),
    );
  }
}

6、Transition类:SizeTransition、FadeTransition、ScaleTransition、AlignTransition、RotationTransition、SlideTransition...

去官方API搜索Transition会发现一大堆已经封装好的Transition,常见的缩放、渐隐渐现、旋转等都有,Transition也是继承自AnimatedWidget,就相当于一个父容器,在你需要实现动画的组件外包一层Transition组件,并传入需要的Animation对象即可,controller同上面代码:

/**
 * Transition类
 */
class Animation3 extends StatefulWidget {
  _Animation3State createState() => new _Animation3State();
}

class _Animation3State extends State<Animation3> with TickerProviderStateMixin {
  AnimationController controller;
  Animation<double> animation;

  initState() {
    super.initState();
    controller = new AnimationController(
        duration: const Duration(milliseconds: 2000), vsync: this);
    animation = new CurvedAnimation(parent: controller, curve: Curves.bounceOut);

    //实现动画循环播放
    animation.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        controller.reverse();
      } else if (status == AnimationStatus.dismissed) {
        controller.forward();
      }
    });

    controller.forward();
  }

  Widget build(BuildContext context) {
    //包裹缩放动画
    return  ScaleTransition(
      scale: animation,
      //包裹旋转动画
      child: RotationTransition(
        turns: animation,
        child: Center(
          child: Text('ScaleTransition + RotationTransition'),
        ),
      ),
    );

  }

  dispose() {
    controller.dispose();
    super.dispose();
  }
}

7、其他

以上是根据中文教程的学习笔记,看到别人写的demo,感觉这种写法更舒服,学习 Flutter知识点: Animation

相关文章

  • 五、Flutter之动画

    主要参考:https://flutterchina.club/animations/ ,这里有很系统的讲解,要深入...

  • Flutter 动画效果

    在动画方面 Flutter 提供了 Animation 类提供使用。 动画 Flutter 中创建动画,请创建名为...

  • Flutter动画animation

    参考 动画 flutter中动画抽象 划重点 Flutter 中的动画系统基于Animation对象,widget...

  • Flutter中的动画

    Flutter中的动画 Flutter中的动画 https://flutterchina.club/tutoria...

  • 《Flutter攻略》正式开坑

    在之前的一篇博客《Flutter攻略》之Animation运行原理中我简单介绍了Flutter框架中动画的基本原理...

  • Flutter从入门到写出完整App Day12

    20.3.27 Flutter实现动画 Flutter有自己的渲染闭环 一. 动画API认识 1. Animati...

  • Flutter 动画之 Tween

    在 Flutter 中,有一种动画类型叫 Tween ,它主要是弥补 AnimationController 动画...

  • Flutter 动画之 AnimationController

    Animation Animation 抽象类,不直接使用,一般通过 AnimationController 来使...

  • Flutter了解之动画

    动画可以改善用户体验。在任何系统的UI框架中,动画实现的原理都和电影的原理一样,即:在一段时间内,快速地多次改变U...

  • Flutter 动画之 Animation

    1.前言 1.1:Flutter动画中: 首先要看的是Flutter中动画的几个类之间的关系: 主角当然是我们的A...

网友评论

      本文标题:五、Flutter之动画

      本文链接:https://www.haomeiwen.com/subject/rogayqtx.html