一、动画关键类的源码分析
1、Animation
Animation没有做什么与动画有关的事情,它只是记录了动画的“状态”、当前的“值”和一些注册回调接口的方法。
abstract class Animation<T> extends Listenable implements ValueListenable<T> { const Animation(); // "值"变化的回调 @override void addListener(VoidCallback listener); @override void removeListener(VoidCallback listener); // 状态回调 void addStatusListener(AnimationStatusListener listener); void removeStatusListener(AnimationStatusListener listener); // 动画状态 AnimationStatus get status; // 动画当前“值” @override T get value; bool get isDismissed => status == AnimationStatus.dismissed; bool get isCompleted => status == AnimationStatus.completed; //... }
2、Tween
Tween记录了一个区间的begin和end。举个例子来说:begin=100 end=200
- t=0.1 lerp() = 110
- t=0.5 lerp() = 150
- t=1.0 lerp() = 200
class Tween<T extends dynamic> extends Animatable<T> { //... // 起始值 T begin; // 结束值 T end; // 计算在特定区间某个时刻的返回值 // t是[0.0,1.0]在某个时刻的比例系数 @protected T lerp(double t) { assert(begin != null); assert(end != null); return begin + (end - begin) * t; } // 外部调用值的变换 @override T transform(double t) { if (t == 0.0) return begin; if (t == 1.0) return end; return lerp(t); } //... }
我们在使用Tween的时候,必须调用Tween.animate()方法。其animate()方法是Tween继承自Animatable<T>类而来的。
// 创建一个Animation anim = Tween<Offset>(begin: Offset(0, 0),end: Offset(0, 2),).animate(_controller); // 位移Tween类中,继承自Animatable<T>类 Animation<T> animate(Animation<double> parent) { return _AnimatedEvaluation<T>(parent, this); } class _AnimatedEvaluation<T> extends Animation<T> with AnimationWithParentMixin<double> { //... @override final Animation<double> parent; // 这个变量就是Tween final Animatable<T> _evaluatable; @override T get value => _evaluatable.evaluate(parent); //... }
由此可以得出animation.value的值来自Tween.evaluate().
3、AnimationController
AnimationController的实现相比较其它的动画核心类来说会比较复杂。那本文章就从两个方面简单分析一下AnimationController的实现。
- AnimationController的声明
- AnimationController实现了两个比较重要的Mixin,一个动画值变化的Listener(AnimationLocalListenersMixin),另一个是动画状态改变的Listener(AnimationLocalStatusListenersMixin)。这里就不帖两个Listener的源代码了,感兴趣的可以去Flutter SDK看一下。
// AnimationController的声明 class AnimationController extends Animation<double> with AnimationEagerListenerMixin, AnimationLocalListenersMixin, AnimationLocalStatusListenersMixin {
- AnimationController的构造函数
AnimationController可以接收很多参数,其中最重要的就是@required TickerProvider vsync,因为它才是动画动起来的根本原因(下面会讲)。
AnimationController({ double value, this.duration,// 动画执行时间 this.reverseDuration,// 动画反向执行时的时间长度(默认和duration相同) this.debugLabel,//debug模式下使用的标签 this.lowerBound = 0.0,// 动画执行完一遍回到的值 this.upperBound = 1.0,// 动画完成的值 this.animationBehavior = AnimationBehavior.normal,// 动画行为(一遍还是重复执行) @required TickerProvider vsync, }) : assert(lowerBound != null), assert(upperBound != null), assert(upperBound >= lowerBound), assert(vsync != null), _direction = _AnimationDirection.forward { _ticker = vsync.createTicker(_tick);// 计时器 _internalSetValue(value ?? lowerBound); }
4、CurvedAnimation
CurvedAnimation是一个非线性曲线的Animation,它继承Animation,它与Animation的区别是在取值的时候按照特定非线性曲线函数生成的值。
// 该函数的具体实现方式 @override double get value { final Curve activeCurve = _useForwardCurve ? curve : reverseCurve; final double t = parent.value; if (activeCurve == null) return t; if (t == 0.0 || t == 1.0) { assert(() { final double transformedValue = activeCurve.transform(t); final double roundedTransformedValue = transformedValue.round().toDouble(); if (roundedTransformedValue != t) { throw FlutterError( 'Invalid curve endpoint at $t. ' 'Curves must map 0.0 to near zero and 1.0 to near one but ' '${activeCurve.runtimeType} mapped $t to $transformedValue, which ' 'is near $roundedTransformedValue.' ); } return true; }()); return t; } return activeCurve.transform(t); }
5、SingleTickerProviderStateMixin
我们创建动画的时候,必须要传递一个TickerProvider参数,SingleTickerProviderStateMixin继承TickerProvider。它本身有两个作用:
- 创建动画计时器。
- 关联Widget生命周期(实际上给了Ticker)。
@optionalTypeArgs mixin SingleTickerProviderStateMixin<T extends StatefulWidget> on State<T> implements TickerProvider { Ticker _ticker; // 创建Ticker @override Ticker createTicker(TickerCallback onTick) { assert(() { if (_ticker == null) return true; throw FlutterError( 'xxxxxxx' ); }()); _ticker = Ticker(onTick, debugLabel: kDebugMode ? 'created by $this' : null); return _ticker; } //... @override void didChangeDependencies() { // 关联widget的生命周期,实际上传给了Ticker if (_ticker != null) _ticker.muted = !TickerMode.of(context); super.didChangeDependencies(); } //... }
二、动画动起来的过程
这时候我们在外面通过anim.addListener(() {setState(() {});});不断的视图层进行重绘,则控件便动了起来。
三、总结
- 抽象类Animation仅仅保存了动画状态和回调函数。
- AnimationController和CurvedAnimation都继承Animation。
- AnimationController是动画的控制器,控制动画的开始和结束,接收动画执行的时间。
- Tween用于限定动画的值的区间。
- SingleTickerProviderStateMixin用于创建Ticker和绑定Widget生命周期。
- Ticker是一个时间定时器,每一个动画帧每一个动画帧都会调用回调函数。
参考文献:1、感谢Flutter中文网提供的资料。2、感谢简书博主