Flutter 源码学习 pt.4,Ticker, TickerProvider

261 阅读1分钟

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等方法,解决两者之间的连接和断链。