美文网首页Flutter
Flutter动画--->了解篇

Flutter动画--->了解篇

作者: 谢尔顿 | 来源:发表于2019-11-15 12:55 被阅读0次

    1. 一个简单例子

    我们通过一个下面一个简单的放大动画来了解动画中相关的Api。

    import 'package:flutter/animation.dart';
    import 'package:flutter/material.dart';
    
    class HomeApp extends StatefulWidget {
      _HomeAppState createState() => new _HomeAppState();
    }
    
    class _HomeAppState extends State<HomeApp> with SingleTickerProviderStateMixin {
      Animation<double> animation;
      AnimationController controller;
    
      initState() {
        super.initState();
        controller = new AnimationController(
            duration: const Duration(milliseconds: 2000), vsync: this);
        animation = new Tween(begin: 20.0, end: 300.0).animate(controller)
          ..addListener(() {
            setState(() {
              // the state that has changed here is the animation object’s value
            });
          });
      }
    
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: Text('一个简单的放大动画'),
            ),
            body: new Center(
              child: Column(
                children: <Widget>[
                  new Container(
                    margin: new EdgeInsets.symmetric(vertical: 10.0),
                    height: animation.value,
                    width: animation.value,
                    child: new FlutterLogo(),
                  ),
                  FlatButton(
                    onPressed: () {
                      controller.forward();
                    },
                    child: Text('放大'),
                  )
                ],
              ),
            ),
          ),
        );
      }
    
      dispose() {
        controller.dispose();
        super.dispose();
      }
    }
    
    void main() {
      runApp(new HomeApp());
    }
    
    

    从上述代码中,我们知道要实现一个简单的缩放动画,我们需要了解下面的api,

    • Animation
      该对象是Flutter动画库中的一个核心类,拥有当前动画的当前状态(例如它是开始、停止还是向前或向后移动)以及通过value获取动画的当前值,但该对象本身和UI渲染没有任何关系,Animation可以生成除double之外的其他类型值,如:Animation<Color>或Animation<Size>。
    • AnimationController
      主要是用来管理Animation的。该类派生自Animation<double>。默认情况下,AnimationController在给定的时间段内会线性的生成0.0到1.0之间的数字。当创建一个AnimationController时,需要传递一个vsync参数,存在vsync时会使得当动画的UI不在当前屏幕时,消耗不必要的资源。
    • Tween
      默认情况下,AnimationController对象的范围从0.0到1.0,如果我们需要不同的数据类型,则可以使用Tween来配置动画以生成不同的范围活数据类型的值。
    • addListener
      是动画的监听器,只要动画的值发生变化就会调用监听器,因此我们可以常用监听器来更新我们的UI界面。

    2. AnimatedWidget

    上述例子中,我们最终是在addListener中利用setState方法来给widget添加动画,而AnimatedWidget的相关系列将会帮我们省略掉这一步,Flutter API提供的关于AnimatedWidget的示例包括:AnimatedBuilder、AnimatedModalBarrier、DecoratedBoxTransition、FadeTransition、PositionedTransition、RelativePositionedTransition、RotationTransition、ScaleTransition、SizeTransition、SlideTransition。

    import 'package:flutter/material.dart';
    
    class AnimatedLogo extends AnimatedWidget {
      AnimatedLogo({Key key, Animation<double> animation})
          : super(key: key, listenable: animation);
      @override
      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(),
          ),
        );
      }
    }
    
    class HomeApp extends StatefulWidget {
      _HomeAppState createState() => new _HomeAppState();
    }
    
    class _HomeAppState extends State<HomeApp> with SingleTickerProviderStateMixin {
      Animation<double> animation;
      AnimationController controller;
    
      initState() {
        super.initState();
        controller = new AnimationController(
            duration: const Duration(milliseconds: 2000), vsync: this);
        animation = new Tween(begin: 20.0, end: 300.0).animate(controller)
          ..addListener(() {
            setState(() {
              // the state that has changed here is the animation object’s value
            });
          });
      }
    
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: Text('一个简单的放大动画'),
            ),
            body: new Center(
              child: Column(
                children: <Widget>[
                  AnimatedLogo(animation: animation),
                  FlatButton(
                    onPressed: () {
                      controller.forward();
                    },
                    child: Text('放大'),
                  )
                ],
              ),
            ),
          ),
        );
      }
    
      dispose() {
        controller.dispose();
        super.dispose();
      }
    }
    
    void main() {
      runApp(new HomeApp());
    }
    
    

    3. 监听动画的状态

    addStatusListener方法可以监听到动画在整个运动期间的状态。

    class _HomeAppState extends State<HomeApp> with SingleTickerProviderStateMixin {
      Animation<double> animation;
      AnimationController controller;
    
      initState() {
        super.initState();
        controller = new AnimationController(
            duration: const Duration(milliseconds: 2000), vsync: this);
        animation = new Tween(begin: 20.0, end: 300.0).animate(controller)
          ..addStatusListener((state){
            print('----->$state');
          });
      }
    

    打印log:

    flutter: ----->AnimationStatus.forward
    flutter: ----->AnimationStatus.completed
    

    下面我们利用该监听来实现一个循环动画,

    class _HomeAppState extends State<HomeApp> with SingleTickerProviderStateMixin {
      Animation<double> animation;
      AnimationController controller;
    
      initState() {
        super.initState();
        controller = new AnimationController(
            duration: const Duration(milliseconds: 2000), vsync: this);
        animation = new Tween(begin: 20.0, end: 300.0).animate(controller)
          ..addStatusListener((state) {
            print('----->$state');
            if (state == AnimationStatus.completed) {
              controller.reverse();
            } else if (state == AnimationStatus.dismissed) controller.forward();
          });
      }
    

    4. 利用AnimatedBuilder进行重构

    上面的例子中我们发现一个问题:动画的logo我们不可以任意的替换。这时我们就可以利用AnimatedWidget来实现。

    class GrowTransition extends StatelessWidget {
      GrowTransition({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),
        );
      }
    }
    
    class HomeApp extends StatefulWidget {
      _HomeAppState createState() => new _HomeAppState();
    }
    
    class _HomeAppState extends State<HomeApp> with SingleTickerProviderStateMixin {
      Animation<double> animation;
      AnimationController controller;
    
      initState() {
        super.initState();
        controller = new AnimationController(
            duration: const Duration(milliseconds: 2000), vsync: this);
        final CurvedAnimation curved =
            new CurvedAnimation(parent: controller, curve: Curves.easeIn);
        animation = new Tween(begin: 20.0, end: 300.0).animate(curved);
      }
    
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: Text('一个简单的放大动画'),
            ),
            body: new Center(
              child: Column(
                children: <Widget>[
                  GrowTransition(
                    child: FlutterLogo(),
                    animation: animation,
                  ),
                  FlatButton(
                    onPressed: () {
                      controller.forward();
                    },
                    child: Text('放大'),
                  )
                ],
              ),
            ),
          ),
        );
      }
    
      dispose() {
        controller.dispose();
        super.dispose();
      }
    }
    
    void main() {
      runApp(new HomeApp());
    }
    
    

    重构之后,我们发现,我们可以将logo替换成任何我们想要的一个widget。

    5. 并行动画

    在上面动画的基础上我们再给logo添加一个透明度变化的动画。下面的例子中我们将学会如何在同一个动画控制器上使用多个Tween,其中每个Tween管理动画中的不同效果。

    class AnimatedLogo extends AnimatedWidget {
      AnimatedLogo({Key key, Animation<double> animation})
          : super(key: key, listenable: animation);
      static final _opacityTween = new Tween(begin: 0.1, end: 1.0);
      static final _sizeTween = new Tween(begin: 0.0, end: 300);
    
      @override
      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(),
            ),
          ),
        );
      }
    }
    
    class HomeApp extends StatefulWidget {
      _HomeAppState createState() => new _HomeAppState();
    }
    
    class _HomeAppState extends State<HomeApp> with SingleTickerProviderStateMixin {
      Animation<double> animation;
      AnimationController controller;
    
      initState() {
        super.initState();
        controller = new AnimationController(
            duration: const Duration(milliseconds: 2000), vsync: this);
        animation = new CurvedAnimation(parent: controller, curve: Curves.easeIn);
    
        animation.addStatusListener((status) {
          if (status == AnimationStatus.completed) {
            controller.reverse();
          } else if (status == AnimationStatus.dismissed) {
            controller.forward();
          }
        });
      }
    
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(
              title: Text('一个简单的放大动画'),
            ),
            body: new Center(
              child: Column(
                children: <Widget>[
                  AnimatedLogo(
                    animation: animation,
                  ),
                  FlatButton(
                    onPressed: () {
                      controller.forward();
                    },
                    child: Text('放大'),
                  )
                ],
              ),
            ),
          ),
        );
      }
    
      dispose() {
        controller.dispose();
        super.dispose();
      }
    }
    
    void main() {
      runApp(new HomeApp());
    }
    
    

    相关文章

      网友评论

        本文标题:Flutter动画--->了解篇

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