Ticker和TickerProvider
Ticker断续器,又称钟摆,由SchedulerBinding.scheduleFrameCallback触发。TickerProvider提供创建Ticker的接口。TickerFuture扩展了Feature,提供了orCancel,在异常取消时报错。
他们三者,组成了对帧的监听,监听代码
@protected
void scheduleTick({ bool rescheduling = false }) {
assert(!scheduled);
assert(shouldScheduleTick);
_animationId = SchedulerBinding.instance.scheduleFrameCallback(_tick, rescheduling: rescheduling);
}
其中_animationId记录正在被调度的帧计数,通过bool get scheduled => _animationId != null 判断Ticker正在运行。
// muted 被 Provider调用方停止,isActive 是 start是否被调用,scheduled 当前帧是否已经被调用
bool get shouldScheduleTick => !muted && isActive && !scheduled;
从高层设计来看,Ticker的设计就是为了保证每个有效帧都会触发TickerCallback, 保证动画的连贯性,如果其中帧的渲染时长超过单帧时间,_onTick(timeStamp - _startTime!);, 可以保证动画时间不会超出约定时间。
我们看一下在AnimationController中如何使用
void _tick(Duration elapsed) {
// 从首次tick到现在的时间
_lastElapsedDuration = elapsed;
final double elapsedInSeconds = elapsed.inMicroseconds.toDouble() / Duration.microsecondsPerSecond;
assert(elapsedInSeconds >= 0.0);
// 根据仿真机得到当下时间的数据
_value = clampDouble(_simulation!.x(elapsedInSeconds), lowerBound, upperBound);
if (_simulation!.isDone(elapsedInSeconds)) {
_status = (_direction == _AnimationDirection.forward) ?
AnimationStatus.completed :
AnimationStatus.dismissed;
stop(canceled: false);
}
// 通知UI更新
notifyListeners();
_checkStatusChanged();
}
以及仿真机,如何组合时间和速率, 在某一个帧,得到正确的数值。
@override
double x(double timeInSeconds) {
final double t = clampDouble(timeInSeconds / _durationInSeconds, 0.0, 1.0);
if (t == 0.0) {
return _begin;
} else if (t == 1.0) {
return _end;
} else {
// 默认插值器
return _begin + (_end - _begin) * _curve.transform(t);
}
}
总结:
Ticker 的作用像是一个 SchedulerBinding 帧的调度和 AnimationController等需要特例监听动画帧回调的的桥梁,给双方都提供一些方法,例如set muted(bool value)和stop等方法,解决两者之间的连接和断链。