先写个简单动画的例子, 代码如下:
class _AnimationSampleState extends State
with SingleTickerProviderStateMixin {
Animation animation;
AnimationController controller;
@override
void initState() {
super.initState();
controller = AnimationController(
duration: const Duration(milliseconds: 2000), vsync: this);
CurvedAnimation curve = CurvedAnimation(parent: controller, curve: Curves.easeOut);
animation = Tween(begin: 0.0, end: 300.0).animate(curve)
..addListener(() {
setState(() {
// the state that has changed here is the animation object’s value
});
});
controller.forward();
}
Widget build(BuildContext context) {
return Center(
child: Container(
margin: EdgeInsets.symmetric(vertical: 10.0),
height: animation.value,
width: animation.value,
child: FlutterLogo(),
),
);
}
dispose() {
controller.dispose();
super.dispose();
}
}
AnimationController
先看下AnimationController的声明
class AnimationController extends Animation
with AnimationEagerListenerMixin, AnimationLocalListenersMixin, AnimationLocalStatusListenersMixin {
AnimationEagerListenerMixin
, AnimationLocalListenersMixin
, AnimationLocalStatusListenersMixin
都继成自_ListenerMixin
.
abstract class _ListenerMixin {
// This class is intended to be used as a mixin, and should not be
// extended directly.
factory _ListenerMixin._() => null;
void didRegisterListener();
void didUnregisterListener();
}
AnimationLocalListenersMixin
代码如下,
abstract class AnimationLocalListenersMixin extends _ListenerMixin {
factory AnimationLocalListenersMixin._() => null;
final ObserverList _listeners = new ObserverList();
void addListener(VoidCallback listener) {
didRegisterListener();
_listeners.add(listener);
}
void removeListener(VoidCallback listener) {
_listeners.remove(listener);
didUnregisterListener();
}
void notifyListeners() {
final List localListeners = new List.from(_listeners);
for (VoidCallback listener in localListeners) {
try {
if (_listeners.contains(listener))
listener();
} catch (exception, stack) {
...
}
}
}
}
AnimationLocalStatusListenersMixin
代码如下
abstract class AnimationLocalStatusListenersMixin extends _ListenerMixin {
factory AnimationLocalStatusListenersMixin._() => null;
final ObserverList _statusListeners = new ObserverList();
void addStatusListener(AnimationStatusListener listener) {
didRegisterListener();
_statusListeners.add(listener);
}
void removeStatusListener(AnimationStatusListener listener) {
_statusListeners.remove(listener);
didUnregisterListener();
}
void notifyStatusListeners(AnimationStatus status) {
final List localListeners = new List.from(_statusListeners);
for (AnimationStatusListener listener in localListeners) {
try {
if (_statusListeners.contains(listener))
listener(status);
} catch (exception, stack) {
...
}
}
}
}
这2个类就是普通的观察者模型, 实现了注册事件/移除事件/队列事件通知. 前者为value变化通知, 后者为状态变更通知.
而AnimationEagerListenerMixin
, 则什么也没实现. 不知道何用.
abstract class AnimationEagerListenerMixin extends _ListenerMixin {
factory AnimationEagerListenerMixin._() => null;
@override
void didRegisterListener() { }
@override
void didUnregisterListener() { }
@mustCallSuper
void dispose() { }
}
Animation
abstract class Animation extends Listenable implements ValueListenable {
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;
@override
String toString() {
return '${describeIdentity(this)}(${toStringDetails()})';
}
}
Animation主要暴露了事件注册接口, 状态以及value查询接口.
Tween
abstract class Animatable {
const Animatable();
T evaluate(Animation animation);
Animation animate(Animation parent) {
return new _AnimatedEvaluation(parent, this);
}
Animatable chain(Animatable parent) {
return new _ChainedEvaluation(parent, this);
}
}
class Tween extends Animatable {
Tween({ this.begin, this.end });
T begin;
T end;
T lerp(double t) {
assert(begin != null);
assert(end != null);
return begin + (end - begin) * t;
}
@override
T evaluate(Animation animation) {
final double t = animation.value;
if (t == 0.0)
return begin;
if (t == 1.0)
return end;
return lerp(t);
}
@override
bool operator ==(dynamic other) {
if (identical(this, other))
return true;
if (other.runtimeType != runtimeType)
return false;
final Tween typedOther = other;
return begin == typedOther.begin
&& end == typedOther.end;
}
@override
int get hashCode => hashValues(begin, end);
@override
String toString() => '$runtimeType($begin \u2192 $end)';
}
Tween继承自Animatable, 定义了begin和end2个成员. evaluate方法通过Animation的value来评估当前的值. 比如begin为100, end为200.
- Animation.value=0.0时, evaluate的值为100.
- Animation.value=0.1时, evaluate的值为110.
- Animation.value=0.75时, evaluate的值为175.
- Animation.value=1.0时, evaluate的值为200.
而使用Tween对象, 必须调用Tween的animate()
方法.
Animation animate(Animation parent) {
return new _AnimatedEvaluation(parent, this);
}
内部构建了_AnimatedEvaluation
对象, 传递了2个构造参数Animation
对象(示例代码中是CurvedAnimation)和Tween对象.
_AnimatedEvaluation
代码如下
class _AnimatedEvaluation extends Animation with AnimationWithParentMixin {
_AnimatedEvaluation(this.parent, this._evaluatable);
@override
final Animation parent;
final Animatable _evaluatable;
@override
T get value => _evaluatable.evaluate(parent);
@override
String toString() {
return '$parent\u27A9$_evaluatable\u27A9$value';
}
@override
String toStringDetails() {
return '${super.toStringDetails()} $_evaluatable';
}
}
可以得出animation.value
的值来自于Tween.evaluate(CurvedAnimation.value)
.
CurvedAnimation
class CurvedAnimation extends Animation with AnimationWithParentMixin {
CurvedAnimation({
@required this.parent,
@required this.curve,
this.reverseCurve
}) : assert(parent != null),
assert(curve != null) {
_updateCurveDirection(parent.status);
parent.addStatusListener(_updateCurveDirection);
}
@override
final Animation parent;
Curve curve;
Curve reverseCurve;
AnimationStatus _curveDirection;
void _updateCurveDirection(AnimationStatus status) {
switch (status) {
case AnimationStatus.dismissed:
case AnimationStatus.completed:
_curveDirection = null;
break;
case AnimationStatus.forward:
_curveDirection ??= AnimationStatus.forward;
break;
case AnimationStatus.reverse:
_curveDirection ??= AnimationStatus.reverse;
break;
}
}
bool get _useForwardCurve {
return reverseCurve == null || (_curveDirection ?? parent.status) != AnimationStatus.reverse;
}
@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 ...
);
}
return true;
}());
return t;
}
return activeCurve.transform(t);
}
@override
String toString() {
...
}
}
可以看出CurvedAnimation同AnimationController一样继承了Animation, 主要对value做了一个函数变换(插值器). 另外还实现了反转功能. 其构造函数需要提供一个Animation对象和Curves(插值器,函数变换)对象.
Curves内置的几种插值器
插值器类
接口代码如下:
abstract class Curve {
const Curve();
double transform(double t);
Curve get flipped => new FlippedCurve(this);
@override
String toString() {
return '$runtimeType';
}
}
我们自定义一个插值器, 只需要实现transform
方法即可. 比如最简单的线性插值器, 直接返回t
即可.
class _Linear extends Curve {
const _Linear._();
@override
double transform(double t) => t;
}
总结
- AnimationController和CurvedAnimation都继承自Animation, 可以注册事件回调.
- CurvedAnimation是动画的插值器, 用来改变动画变化的过程.
- AnimationController是动画的控制器, 接收时间参数, 控制动画的开始和结束.
- Tween用于提供起始值和最终值.
这3个类的关系讲清楚了, 还漏掉了最后一点, 动画是如何被触发不断更新的.在构造AnimationController有个vsync属性.
再看下AnimationController的构造函数.
AnimationController({
double value,
this.duration,
this.debugLabel,
this.lowerBound: 0.0,
this.upperBound: 1.0,
@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);
}
vsync属性是TickerProvider对象. 例子中我们实现了SingleTickerProviderStateMixin对象.
abstract class SingleTickerProviderStateMixin extends State implements TickerProvider {
factory SingleTickerProviderStateMixin._() => null;
Ticker _ticker;
@override
Ticker createTicker(TickerCallback onTick) {
assert(() {
if (_ticker == null)
return true;
throw new FlutterError(
...
);
}());
_ticker = new Ticker(onTick, debugLabel: 'created by $this');
return _ticker;
}
@override
void dispose() {
assert(() {
if (_ticker == null || !_ticker.isActive)
return true;
throw new FlutterError(
...
);
}());
super.dispose();
}
@override
void didChangeDependencies() {
if (_ticker != null)
_ticker.muted = !TickerMode.of(context);
super.didChangeDependencies();
}
...
}
SingleTickerProviderStateMixin
里包含了一个Ticker
对象, 而Ticker
对象里是由底层SchedulerBinding
触发动画更新回调, 导致onTick方法被回调. 也就是AnimationController
里的_tick
方法. 代码如下:
void _tick(Duration elapsed) {
_lastElapsedDuration = elapsed;
final double elapsedInSeconds = elapsed.inMicroseconds.toDouble() / Duration.microsecondsPerSecond;
assert(elapsedInSeconds >= 0.0);
_value = _simulation.x(elapsedInSeconds).clamp(lowerBound, upperBound);
if (_simulation.isDone(elapsedInSeconds)) {
_status = (_direction == _AnimationDirection.forward) ?
AnimationStatus.completed :
AnimationStatus.dismissed;
stop(canceled: false);
}
notifyListeners();
_checkStatusChanged();
}
@override
double get value => _value;
这个方法会不断被底层回调, 更新value值, 检查状态变更, 然后触发回调事件.
关于value值变化过程.
- 底层触发SingleTickerProviderStateMixin的tick().
- AnimationController的_tick()改变value.
- CurvedAnimation从parent也就是AnimationController中的value做插值变化得到新的value.
- Tween再根据CurvedAnimation的value, 结合begin和end, 得到最终使用的value.