美文网首页
Flutter动画实现原理

Flutter动画实现原理

作者: 最近不在 | 来源:发表于2018-08-07 20:42 被阅读350次

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

    class _AnimationSampleState extends State<AnimationSampleState>
        with SingleTickerProviderStateMixin {
      Animation<double> 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<double>
      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<VoidCallback> _listeners = new ObserverList<VoidCallback>();
    
      void addListener(VoidCallback listener) {
        didRegisterListener();
        _listeners.add(listener);
      }
    
      void removeListener(VoidCallback listener) {
        _listeners.remove(listener);
        didUnregisterListener();
      }
    
      void notifyListeners() {
        final List<VoidCallback> localListeners = new List<VoidCallback>.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<AnimationStatusListener> _statusListeners = new ObserverList<AnimationStatusListener>();
    
      void addStatusListener(AnimationStatusListener listener) {
        didRegisterListener();
        _statusListeners.add(listener);
      }
    
      void removeStatusListener(AnimationStatusListener listener) {
        _statusListeners.remove(listener);
        didUnregisterListener();
      }
    
      void notifyStatusListeners(AnimationStatus status) {
        final List<AnimationStatusListener> localListeners = new List<AnimationStatusListener>.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<T> extends Listenable implements ValueListenable<T> {
      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<T> {
      const Animatable();
    
      T evaluate(Animation<double> animation);
    
      Animation<T> animate(Animation<double> parent) {
        return new _AnimatedEvaluation<T>(parent, this);
      }
    
      Animatable<T> chain(Animatable<double> parent) {
        return new _ChainedEvaluation<T>(parent, this);
      }
    }
    
    class Tween<T extends dynamic> extends Animatable<T> {
      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<double> 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<T> 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<T> animate(Animation<double> parent) {
        return new _AnimatedEvaluation<T>(parent, this);
      }
    

    内部构建了_AnimatedEvaluation对象, 传递了2个构造参数Animation<double>对象(示例代码中是CurvedAnimation)和Tween对象.

    _AnimatedEvaluation代码如下

    class _AnimatedEvaluation<T> extends Animation<T> with AnimationWithParentMixin<double> {
      _AnimatedEvaluation(this.parent, this._evaluatable);
    
      @override
      final Animation<double> parent;
    
      final Animatable<T> _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<double> with AnimationWithParentMixin<double> {
      CurvedAnimation({
        @required this.parent,
        @required this.curve,
        this.reverseCurve
      }) : assert(parent != null),
           assert(curve != null) {
        _updateCurveDirection(parent.status);
        parent.addStatusListener(_updateCurveDirection);
      }
    
      @override
      final Animation<double> 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<T extends StatefulWidget> extends State<T> 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动画实现原理

          本文链接:https://www.haomeiwen.com/subject/nnqzvftx.html