美文网首页
Flutter动画animation

Flutter动画animation

作者: 磊简单 | 来源:发表于2019-03-05 14:57 被阅读0次

参考

动画

在任何系统的UI框架中,动画实现的原理都是相同的,即:
在一段时间内,快速地多次改变UI外观,由于人眼会产生视觉暂留,最终看到的就是一个“连续”的动画,这和电影的原理是一样的,而UI的一次改变称为一个动画帧,对应一次屏幕刷新,而决定动画流畅度的一个重要指标就是帧率FPS(Frame Per Second),指每秒的动画帧数。很明显,帧率越高则动画就会越流畅。
一般情况下,对于人眼来说,动画帧率超过16FPS,就比较流畅了,超过32FPS就会非常的细腻平滑,而超过32FPS基本就感受不到差别了。由于动画的每一帧都是要改变UI输出,所以在一个时间段内连续的改变UI输出是比较耗资源的,对设备的软硬件系统要求都较高,所以在UI系统中,动画的平均帧率是重要的性能指标,而在Flutter中,理想情况下是可以实现60FPS的,这和原生应用动画基本是持平的。

flutter中动画抽象

为了方便开发者创建动画,不同的UI系统对动画都进行了一些抽象,比如在Android中可以通过XML来描述一个动画然后设置给View。Flutter中也对动画进行了抽象,主要涉及Tween、Animation、Curve、Controller这些角色。

划重点

Animation对象是Flutter动画库中的一个核心类,它生成指导动画的值。
Animation对象知道动画的当前状态(例如,它是开始、停止还是向前或向后移动),但它不知道屏幕上显示的内容。
AnimationController管理Animation。
CurvedAnimation 将过程抽象为一个非线性曲线.
Tween在正在执行动画的对象所使用的数据范围之间生成值。例如,Tween可能会生成从红到蓝之间的色值,或者从0到255。
使用Listeners和StatusListeners监听动画状态改变。
  • Flutter 中的动画系统基于Animation对象,widget可以在build 函数中对子widget进行属性赋值时取Animation对象的value,并可以监听动画的状态改变。

Animation<Double>

在Flutter中,Animation对象本身和UI渲染没有任何关系。Animation是一个抽象类,它拥有其当前值和状态(完成或停止)。其中一个比较常用的Animation类是Animation<double>。

Flutter中的Animation对象是一个在一段时间内依次生成一个区间之间值的类。Animation对象的输出可以是线性的、曲线的、一个步进函数或者任何其他可以设计的映射。 根据Animation对象的控制方式,动画可以反向运行,甚至可以在中间切换方向。

Animation还可以生成除double之外的其他类型值,如:Animation<Color> 或 Animation<Size>。

Animation对象有状态。可以通过访问其value属性获取动画的当前值。

Animation对象本身和UI渲染没有任何关系。

AnimationController

AnimationController是一个特殊的Animation对象,在屏幕刷新的每一帧,就会生成一个新的值。默认情况下,AnimationController在给定的时间段内会线性的生成从0.0到1.0的数字。
AnimationController派生自Animation<double>,因此可以在需要Animation对象的任何地方使用。 但是,AnimationController具有控制动画的其他方法。例如,.forward()方法可以启动动画。数字的产生与屏幕刷新有关,因此每秒钟通常会产生60个数字,在生成每个数字后,每个Animation对象调用添加的Listener对象。
AnimationController派生自Animation<double>,因此可以在需要Animation对象的任何地方使用。 但是,AnimationController具有控制动画的其他方法。例如,.forward()方法可以启动动画。数字的产生与屏幕刷新有关,因此每秒钟通常会产生60个数字,在生成每个数字后,每个Animation对象调用添加的Listener对象。

示例

  • 直接用AnimationContrller生成动画
class _AnimationTestState extends State<AnimationTest> with SingleTickerProviderStateMixin{
  Animation<double> _animation;
  AnimationController _animationController;
  @override
  void initState() {
    super.initState();
//lowerBound和upperBound值只能在0.0到1.0之间变化
    _animationController = new AnimationController(vsync: this,lowerBound: 0.0,upperBound: 0.5,duration: new Duration(milliseconds: 3000));
// 添加监听
    _animationController.addListener((){
      setState(() { });
    });
// 开启动画
    _animationController.forward();
  }
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('animation'),
      ),
      body: new Center(
        child: new Container(
          // 取AnimationController 对象value直接用
          width: _animationController.value*300,
          height: _animationController.value*300,
          child: new FlutterLogo(),
        ),
      ),
    );
  }
 @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }
}

Tween

  • 默认情况下,AnimationController对象的范围从0.0到1.0。如果您需要不同的范围或不同的数据类型,则可以使用Tween来配置动画以生成不同的范围或数据类型的值。
  • Tween是一个无状态(stateless)对象,需要begin和end值。Tween的唯一职责就是定义从输入范围到输出范围的映射。输入范围通常为0.0到1.0,但这不是必须的。
  • Tween继承自Animatable<T>,而不是继承自Animation<T>。Animatable与Animation相似,不是必须输出double值。
  • Tween对象不存储任何状态。相反,它提供了evaluate(Animation<double> animation)方法将映射函数应用于动画当前值。 Animation对象的当前值可以通过value()方法取到。evaluate函数还执行一些其它处理,例如分别确保在动画值为0.0和1.0时返回开始和结束状态。
  • 要使用Tween对象,请调用其animate()方法,传入一个控制器对象。

示例:

class _AnimationTestState extends State<AnimationTest> with SingleTickerProviderStateMixin{
  Animation<double> _animation;
  AnimationController _animationController;
  Tween<double> _sizeTween;
  Tween<Color> _colorTween;
  @override
  void initState() {
    super.initState();
    _animationController = new AnimationController(vsync: this,duration: new Duration(milliseconds: 3000));
  //  _animation = new ColorTween(begin: Colors.transparent,end: Colors.amberAccent).animate(_animationController)
//      ..addListener((){
//        setState(() {
//        });
//      });
    _animation = new Tween(begin: 0.0,end: 300.0).animate(_animationController)
     ..addListener((){
        setState(() {
        });
      });
    _animationController.forward();
  }
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('animation'),
      ),
      body: new Center(
        child: new Container(
         // color: _animation.value,
          width: _animation.value,
          height: _animation.value,
        ),
      ),
    );
  }
 @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }
}

并行动画

示例

class _AnimationTestState extends State<AnimationTest> with SingleTickerProviderStateMixin{
  Animation<double> _animation;
  AnimationController _animationController;
  Tween<double> _sizeTween;
  Tween<Color> _colorTween;
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _animationController = new AnimationController(vsync: this,duration: new Duration(milliseconds: 3000));
    _animation = new CurvedAnimation(parent: _animationController, curve: Curves.easeIn)
      ..addListener((){
        setState(() {
        });
      });
    _sizeTween = new Tween(begin: 0.0,end: 300.0);
    _colorTween = new ColorTween(begin: Colors.transparent,end: Colors.amberAccent);

    _animationController.forward();
  }
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('animation'),
      ),
      body: new Center(
        child: new Container(
          color: _colorTween.evaluate(_animation),
          width: _sizeTween.evaluate(_animation),
          height: _sizeTween.evaluate(_animation),
        ),
      ),
    );
  }
 @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }
}

如果做改变大小或透明度的动画,可以直接用FadeTransition、SizeTransition。

示例

class _AnimationTestState extends State<AnimationTest> with SingleTickerProviderStateMixin{
  AnimationController _animationController;
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _animationController = new AnimationController(vsync: this,duration: new Duration(milliseconds: 5000));
    _animationController.forward();
  }
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('animation'),
      ),
      body: new Center(
//        child: new SizeTransition(
//          sizeFactor: _animationController,
//          child: new Container(
//            color: Colors.amberAccent,
//            width: 200.0,
//            height: 200.0,
//          ),
//        ),
        child: new FadeTransition(
          opacity: _animationController,
          child: new Container(
            color: Colors.amberAccent,
            width: 200.0,
            height: 200.0,
          ),
        ),
      ),
    );
  }
 @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }
}

AnimatedWidget

  • AnimatedWidget使用来简化动画的组件,它封装了setState()的调用细节。省去了addListener()和setState().

示例

// 自定义widget继承AnimatedWidget
class AnimateLog extends AnimatedWidget{
  AnimateLog({Key key,Animation<double> animation})
    :super(key:key,listenable:animation);
  @override
  Widget build(BuildContext context) {
    final Tween<double> tranTween = new Tween<double>(begin: 0.0,end: 300.0);
    final Tween<double> opacTween = new Tween<double>(begin: 0.1,end: 1.0);
    final Animation<double> animation = listenable;
    // TODO: implement build
    return new Opacity(
      opacity: opacTween.evaluate(animation),
      child: new Center(
        child: new Container(
          child: new FlutterLogo(),
          width: tranTween.evaluate(animation),
          height: tranTween.evaluate(animation),
        ),
      ),
    );
  }
}
  • 使用
@override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('animation'),
      ),
      body: new Center(
        child: new AnimateLog(animation: _animation)
      ),
    );
  }

AnimateBuilder

  • 是为了把Widget从动画中剥离出来。

示例

class _AnimationTestState extends State<AnimationTest> with SingleTickerProviderStateMixin{
  AnimationController _animationController;
  Animation<double> _animation;
  @override
  void initState() {
    super.initState();
    _animationController = new AnimationController(vsync: this,duration: new Duration(milliseconds: 5000));
    _animation = Tween(begin: 0.0,end: 300.0).animate(_animationController);
    _animationController.forward();
  }
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('animation'),
      ),
      body: AnimatedBuilder(
        animation: _animation,
        child: new FlutterLogo(),
        builder: (BuildContext context,Widget child){
          return new Center(
             child:new Container(
                height: _animation.value,
                width: _animation.value,
                child: child,
              )
          );
        },
      )
    );
  }
  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }
}
  • 可以单独封装一个动画,然后将Widget传进去,实现动画和Widget分离。

示例

class GrowTransition extends StatelessWidget{
  final Animation<double> animation;
  final Widget child;
  GrowTransition({this.animation,this.child});
  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      child: child,
      animation: animation,
      builder: (BuildContext context,Widget child){
        return new Center(
          child: new Container(
            width: animation.value,
            height: animation.value,
            child: child,
          ),
        );
      },
    );
  }
}
  • 使用
@override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('animation'),
      ),
      body: new GrowTransition(
        child: new FlutterLogo(),
        animation: _animation,
      )
    );
  }

动画监听

  • 可以通过Animation的addStatusListener() 来对动画的状态进行监听,以下是四种动画状态:
枚举值 含义
dismissed 动画在起始点停止
forward 动画正在正向执行
reverse 动画正在反向执行
completed 动画在终点停止

示例

....
    _animationController = new AnimationController(vsync: this,duration: new Duration(milliseconds: 5000));
    _animation = Tween(begin: 0.0,end: 300.0).animate(_animationController);
    _animation.addStatusListener((status){
        if (status == AnimationStatus.completed){
          _animationController.reverse();
        }
        else if (status == AnimationStatus.dismissed){
          _animationController.forward();
        }
    });
    _animationController.forward();
...

待续

相关文章

网友评论

      本文标题:Flutter动画animation

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