深入理解 Flutter 动画原理,一个月成功收割腾讯、阿里、字节 offer
@required TickerProvider vsync,
}) : _direction = _AnimationDirection.forward {
_ticker = vsync.createTicker(_tick); //[见小节 2.1.1]
_internalSetValue(value ?? lowerBound); //[见小节 2.1.3]
}
该方法说明:
AnimationController 初始化过程,一般都设置 duration 和 vsync 初值;
upperBound(上边界值)和 lowerBound(下边界值)都不能为空,且 upperBound 必须大于等于 lowerBound;
创建默认的动画方向为向前(_AnimationDirection.forward);
调用类型为 TickerProvider 的 vsync 对象的 createTicker()方法来创建 Ticker 对象;
TickerProvider 作为抽象类,主要的子类有 SingleTickerProviderStateMixin 和 TickerProviderStateMixin,这两个类的区别就是是否支持创建多个 TickerProvider,这里 SingleTickerProviderStateMixin 为例展开。
2.1.1 createTi
[-> lib/src/widgets/ticker_provider.dart]
mixin SingleTickerProviderStateMixin<T extends StatefulWidget> on State<T> implements TickerProvider {
Ticker _ticker;
Ticker createTicker(TickerCallback onTick) {
//[见小节 2.1.2]
_ticker = Ticker(onTick, debugLabel: 'created by $this');
return _ticker;
}
2.1.2 Ticker 初始化
[-> lib/src/scheduler/ticker.dart]
class Ticker {
Ticker(this._onTick, { this.debugLabel }) {
}
final TickerCallback _onTick;
}
将 AnimationControllerd 对象中的_tick()方法,赋值给 Ticker 对象的_onTick 成员变量,再来看看该_tick 方法。
2.1.3 _internalSetValue
[-> lib/src/animation/animation_controller.dart ::AnimationController]
void _internalSetValue(double newValue) {
_value = newValue.clamp(lowerBound, upperBound);
if (_value == lowerBound) {
_status = AnimationStatus.dismissed;
} else if (_value == upperBound) {
_status = AnimationStatus.completed;
} else {
_status = (_direction == _AnimationDirection.forward) ?
AnimationStatus.forward :
AnimationStatus.reverse;
}
}
根据当前的 value 值来初始化动画状态_status
2.2 forward
[-> lib/src/animation/animation_controller.dart ::AnimationController]
TickerFuture forward({ double from }) {
//默认采用向前的动画方向
_direction = _AnimationDirection.forward;
if (from != null)
value = from;
return _animateToInternal(upperBound); //[见小节 2.3]
}
_AnimationDirection 是枚举类型,有 forward(向前)和 reverse(向后)两个值,也就是说该方法的功能是指从 from 开始向前滑动,
2.3 _animateToInternal
[-> lib/src/animation/animation_controller.dart ::AnimationController]
TickerFuture _animateToInternal(double target, { Duration duration, Curve curve = Curves.linear }) {
double scale = 1.0;
if (SemanticsBinding.instance.disableAnimations) {
switch (animationBehavior) {
case AnimationBehavior.normal:
scale = 0.05;
break;
case AnimationBehavior.preserve:
break;
}
}
Duration simulationDuration = duration;
if (simulationDuration == null) {
final double range = upperBound - lowerBound;
final double remainingFraction = range.isFinite ? (target - _value).abs() / range : 1.0;
//根据剩余动画的百分比来评估仿真动画剩余时长
simulationDuration = this.duration * remainingFraction;
} else if (target == value) {
//已到达动画终点,不再执行动画
simulationDuration = Duration.zero;
}
//停止老的动画[见小节 2.3.1]
stop();
if (simulationDuration == Duration.zero) {
if (value != target) {
_value = target.clamp(lowerBound, upperBound);
notifyListeners();
}
_status = (_direction == _AnimationDirection.forward) ?
AnimationStatus.completed :
AnimationStatus.dismissed;
_checkStatusChanged();
//当动画执行时间已到,则直接结束
return TickerFuture.complete();
}
//[见小节 2.4]
return _startSimulation(_InterpolationSimulation(_value, target, simulationDuration, curve, scale));
}
默认采用的是线性动画曲线 Curves.linear。
2.3.1 AnimationController.stop
void stop({ bool canceled = true }) {
_simulation = null;
_lastElapsedDuration = null;
//[见小节 2.3.2]
_ticker.stop(canceled: canceled);
}
2.3.2 Ticker.stop
[-> lib/src/scheduler/ticker.dart]
void stop({ bool canceled = false }) {
if (!isActive) //已经不活跃,则直接返回
return;
final TickerFuture localFuture = _future;
_future = null;
_startTime = null;
//[见小节 2.3.3]
unscheduleTick();
if (canceled) {
localFuture._cancel(this);
} else {
localFuture._complete();
}
}
2.3.3 Ticker.unscheduleTick
[-> lib/src/scheduler/ticker.dart]
void unscheduleTick() {
if (scheduled) {
SchedulerBinding.instance.cancelFrameCallbackWithId(_animationId);
_animationId = null;
}
}
2.3.4 _InterpolationSimulation 初始化
[-> lib/src/animation/animation_controller.dart ::_InterpolationSimulation]
class?_InterpolationSimulation?extends?Simulation?{
_InterpolationSimulation(this._begin, this._end, Duration duration, this._curve, double scale)
: _durationInSeconds = (duration.inMicroseconds * scale) / Duration.microsecondsPerSecond;
final double _durationInSeconds;
final double _begin;
final double _end;
final Curve _curve;
}
该方法创建插值模拟器对象,并初始化起点、终点、动画曲线以及时长。这里用的 Curve 是线性模型,也就是说采用的是匀速运动。
2.4 _startSimulation
[-> lib/src/animation/animation_controller.dart]
TickerFuture _startSimulation(Simulation simulation) {
_simulation = simulation;
_lastElapsedDuration = Duration.zero;
_value = simulation.x(0.0).clamp(lowerBound, upperBound);
//[见小节 2.5]
final TickerFuture result = _ticker.start();
_status = (_direction == _AnimationDirection.forward) ?
AnimationStatus.forward :
AnimationStatus.reverse;
//[见小节 2.4.1]
_checkStatusChanged();
return result;
}
2.4.1 _checkStatusChanged
[-> lib/src/animation/animation_controller.dart]
void _checkStatusChanged() {
final AnimationStatus newStatus = status;
if (_lastReportedStatus != newStatus) {
_lastReportedStatus = newStatus;
notifyStatusListeners(newStatus); //通知状态改变
}
}
这里会回调_statusListeners 中的所有状态监听器,这里的状态就是指 AnimationStatus 的 dismissed、forward、reverse 以及 completed。
2.5 Ticker.start
[-> lib/src/scheduler/ticker.dart]
TickerFuture start() {
future = TickerFuture.();
if (shouldScheduleTick) {
scheduleTick(); //[见小节 2.6]
}
if (SchedulerBinding.instance.schedulerPhase.index > SchedulerPhase.idle.index &&
SchedulerBinding.instance.schedulerPhase.index < SchedulerPhase.postFrameCallbacks.index)
_startTime = SchedulerBinding.instance.currentFrameTimeStamp;
return _future;
}
此处的 shouldScheduleTick 等于!muted && isActive && !scheduled,也就是没有调度过的活跃状态才会调用 Tick。
2.6 Ticker.scheduleTick
[-> lib/src/scheduler/ticker.dart]
void scheduleTick({ bool rescheduling = false }) {
//[见小节 2.7]
_animationId = SchedulerBinding.instance.scheduleFrameCallback(_tick, rescheduling: rescheduling);
}
此处的_tick 会在下一次 vysnc 触发时回调执行,见小节 2.10。
2.7 scheduleFrameCallback
[-> lib/src/scheduler/binding.dart]
int scheduleFrameCallback(FrameCallback callback, { bool rescheduling = false }) {
//[见小节 2.8]
scheduleFrame();
_nextFrameCallbackId += 1;
_transientCallbacks[_nextFrameCallbackId] = _FrameCallbackEntry(callback, rescheduling: rescheduling);
return _nextFrameCallbackId;
}
将前面传递过来的 Ticker._tick()方法保存在_FrameCallbackEntry 的 callback 中,然后将_FrameCallbackEntry 记录在 Map 类型的_transientCallbacks,
2.8 scheduleFrame
[-> lib/src/scheduler/binding.dart]
void scheduleFrame() {
if (_hasScheduledFrame || !_framesEnabled)
return;
ui.window.scheduleFrame();
_hasScheduledFrame = true;
}
从文章Flutter之setState更新机制,可知此处调用的 ui.window.scheduleFrame(),会注册 vsync 监听。当当下一次 vsync 信号的到来时会执行 handleBeginFrame()。
2.9 handleBeginFrame
[-> lib/src/scheduler/binding.dart:: SchedulerBinding]
void handleBeginFrame(Duration rawTimeStamp) {
Timeline.startSync('Frame', arguments: timelineWhitelistArguments);
_firstRawTimeStampInEpoch ??= rawTimeStamp;
_currentFrameTimeStamp = _adjustForEpoch(rawTimeStamp ?? _lastRawTimeStamp);
if (rawTimeStamp != null)
_lastRawTimeStamp = rawTimeStamp;
评论