Flutter动画实现原理

先写个简单动画的例子, 代码如下:

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内置的几种插值器

Flutter动画实现原理_第1张图片

Flutter动画实现原理_第2张图片

Flutter动画实现原理_第3张图片

插值器类

接口代码如下:

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.

你可能感兴趣的:(Flutter动画实现原理)