[TOC]
详解Animation-2动画组
参考文章:
一、Animation动画组-串行
参考文档:
串行动画的实现方案总共有三种,分别是 监听状态法, Interval时间间隔法, TweenSequence动画序列法.
1、监听状态法
状态监听法主要通过AnimationController监听动画的completed状态,然后再去执行下一个动画,如此往复,直到所有动画完成.
例如现在我们需要实现先执行组件在0.3秒钟往下偏移50个单位,然后再执行在0.6s中组件的颜色由 橘色 变为 红色.
整体Demo代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| class FlutterAnimationWidget extends StatefulWidget { TurnTableLotteryPage({Key key}) : super(key: key); @override _FlutterAnimationWidgetState createState() => _FlutterAnimationWidgetState(); }
class _FlutterAnimationWidgetState extends State<FlutterAnimationWidget> with TickerProviderStateMixin { AnimationController _animationController; Animation<double> _animation; AnimationController _colorAnimationController; Animation<Color> _colorAnimation;
@override void initState() { super.initState(); _animationController = AnimationController(duration: Duration(milliseconds: 300), vsync: this); _animation = Tween<double>(begin: 0, end: 50).animate(_animationController) ..addListener(() { setState(() {}); }); _colorAnimationController = AnimationController(duration: Duration(milliseconds: 600), vsync: this); _colorAnimation = ColorTween(begin: Colors.orangeAccent, end: Colors.redAccent).animate(_colorAnimationController) ..addListener(() { setState(() {}); }); _animationController.addStatusListener((status) { if (status == AnimationStatus.completed) { _colorAnimationController.forward(); }; }); }
void startEasyAnimation() { _animationController.forward(); }
@override void dispose() { _animationController.dispose(); super.dispose(); }
@override Widget build(BuildContext context) { return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Container( width: 200, height: 50, color: _colorAnimation.value, margin: EdgeInsets.only(top: _animation.value), ), FlatButton( onPressed: startEasyAnimation, child: Text( "点击执行最简单动画", style: TextStyle(color: Colors.black38), ), ), ], ), ), ); } }
|
2、Interval时间间隔法
上面的状态监听需要一个动画过程就写一个Controller,而且基本上还要每一个Controller都监听执行完成然后再去启动下一个Controller.如果一个动画过程有十几个,自己想想都是脑瓜子嗡嗡的.所以接下来我们就来介绍第二种方案 - Interval时间间隔法 .
Interval时间间隔法 的整体思路是一个动画Controller控制所有动画的执行.然后每一个动画只需要确认自己在整个动画的时间比重即可.
整体Demo代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| class FlutterAnimationWidget extends StatefulWidget { TurnTableLotteryPage({Key key}) : super(key: key); @override _FlutterAnimationWidgetState createState() => _FlutterAnimationWidgetState(); }
class _FlutterAnimationWidgetState extends State<FlutterAnimationWidget> with TickerProviderStateMixin { AnimationController _animationController; Animation<double> _animation; Animation<Color> _colorAnimation;
@override void initState() { super.initState(); _animationController = AnimationController(duration: Duration(milliseconds: 600), vsync: this); _animation = Tween<double>(begin: 0, end: 50).animate( CurvedAnimation( parent: _animationController, curve: Interval(0.0, 0.5), ), )..addListener(() { setState(() {}); }); _colorAnimation = ColorTween(begin: Colors.orangeAccent, end: Colors.redAccent).animate( CurvedAnimation( parent: _animationController, curve: Interval(0.5, 1.0), ), )..addListener(() { setState(() {}); }); }
void startEasyAnimation() { _animationController.forward(); }
@override void dispose() { _animationController.dispose(); super.dispose(); }
@override Widget build(BuildContext context) { return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Container( width: 200, height: 50, color: _colorAnimation.value, margin: EdgeInsets.only(top: _animation.value), ), FlatButton( onPressed: startEasyAnimation, child: Text( "点击执行最简单动画", style: TextStyle(color: Colors.black38), ), ), ], ), ), ); } }
|
3、TweenSequence动画序列法
上面的两种方案虽然能解决动画组的问题,但是都太过于繁琐,那么有没有一种比较优雅的方案呢?这就需要使用到 TweenSequence 和 TweenSequenceItem 这两个类了. 其中 TweenSequence 是动画组类,TweenSequenceItem 则是用来定义每一个动画的具体实现的类.但是TweenSequence 和 TweenSequenceItem也不是尽善尽美的,它最大的问题就是前后变化的属性值类型必须是一致的.
下面,我们仍然以改变Margin为例, 先让视图组件往上移动50,再让视图 来看看如何使用 TweenSequence 和 TweenSequenceItem 来实现这个动画.
整体代码如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| class FlutterAnimationWidget extends StatefulWidget { TurnTableLotteryPage({Key key}) : super(key: key); @override _FlutterAnimationWidgetState createState() => _FlutterAnimationWidgetState(); }
class _FlutterAnimationWidgetState extends State<FlutterAnimationWidget> with TickerProviderStateMixin { AnimationController _animationController; Animation<double> _animation;
@override void initState() { super.initState(); _animationController = AnimationController(duration: Duration(milliseconds: 600), vsync: this); TweenSequenceItem downMarginItem = TweenSequenceItem<double>( tween: Tween(begin: 1.0, end: 50.0), weight: 50, ); TweenSequenceItem upMarginItem = TweenSequenceItem<double>( tween: Tween(begin: 50.0, end: 100.0), weight: 100, ); TweenSequence tweenSequence = TweenSequence<double>([ downMarginItem, upMarginItem, ]); _animation = tweenSequence.animate(_animationController); _animation.addListener(() { setState(() {}); }); }
void startEasyAnimation() { _animationController.forward(); }
@override void dispose() { _animationController.dispose(); super.dispose(); }
@override Widget build(BuildContext context) { return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Container( width: 200, height: 50, color: Colors.orangeAccent, margin: EdgeInsets.only(top: _animation.value), ), FlatButton( onPressed: startEasyAnimation, child: Text( "点击执行最简单动画", style: TextStyle(color: Colors.black38), ), ), ], ), ), ); } }
|
动画组实现总结
上面三种实现动画组基本上已经说完了,接下来我们就来对比其不同点.
特性 |
监听状态法 |
Interval时间间隔法 |
TweenSequence动画序列法 |
代码简洁度 |
🔅🔅 |
🔅🔅🔅 |
🔅🔅🔅🔅🔅 |
动画是否可交织 |
❌ |
✅ |
❌ |
动画属性是否可以多变 |
✅ |
✅ |
❌ |
动画是否可交织 : 动画可否交织主要是说两个动画之间是否需要上一个动画完全执行完成之后,下一个动画才能执行.
动画属性是否可以多变 : 动画属性多变是指当前动画过程中可变化的属性是否可以有多个,例如同时变化尺寸和颜色等等.