Animation没有作什么与动画有关的事情,它只是记录了动画的“状态”、当前的“值”和一些注册回调接口的方法。app
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; //... }
Tween记录了一个区间的begin和end。举个例子来讲:begin=100 end=200 ide
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().源码分析
AnimationController的实现相比较其它的动画核心类来讲会比较复杂。那本文章就从两个方面简单分析一下AnimationController的实现。动画
// AnimationController的声明 class AnimationController extends Animation<double> with AnimationEagerListenerMixin, AnimationLocalListenersMixin, AnimationLocalStatusListenersMixin {
AnimationController能够接收不少参数,其中最重要的就是@required TickerProvider vsync,由于它才是动画动起来的根本缘由(下面会讲)。ui
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); }
CurvedAnimation是一个非线性曲线的Animation,它继承Animation,它与Animation的区别是在取值的时候按照特定非线性曲线函数生成的值。this
// 该函数的具体实现方式 @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.\n' '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); }
咱们建立动画的时候,必需要传递一个TickerProvider参数,SingleTickerProviderStateMixin继承TickerProvider。它自己有两个做用:lua
@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(() {});});不断的视图层进行重绘,则控件便动了起来。spa
参考文献:一、感谢Flutter中文网提供的资料。二、感谢简书博主debug