Flutter记录自学flutter点点滴滴

Flutter 学习之旅(三十七) Flutter 动画(四)

2020-09-23  本文已影响0人  Tsm_2020

前面介绍AnimatedWidget的时候虽然省略了一部分代码,但是如果自己封装动画的话,还是非常麻烦,这就需要引入新的封装,ImplicitlyAnimatedWidget , ImplicitlyAnimatedWidgetState,

ImplicitlyAnimatedWidget

abstract class ImplicitlyAnimatedWidget extends StatefulWidget {
  /// Initializes fields for subclasses.
  ///
  /// The [curve] and [duration] arguments must not be null.
  const ImplicitlyAnimatedWidget({
    Key key,
    this.curve = Curves.linear,
    @required this.duration,
    this.onEnd,
  }) : assert(curve != null),
       assert(duration != null),
       super(key: key);

  /// The curve to apply when animating the parameters of this container.
  final Curve curve;

  /// The duration over which to animate the parameters of this container.
  final Duration duration;

  /// Called every time an animation completes.
  ///
  /// This can be useful to trigger additional actions (e.g. another animation)
  /// at the end of the current animation.
  final VoidCallback onEnd;

  @override
  ImplicitlyAnimatedWidgetState<ImplicitlyAnimatedWidget> createState();

  @override
  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
    super.debugFillProperties(properties);
    properties.add(IntProperty('duration', duration.inMilliseconds, unit: 'ms'));
  }
}

ImplicitlyAnimatedWidget 是一个抽象类,入参包括druation curve 和一个回调函数 onEnd

ImplicitlyAnimatedWidgetState

abstract class ImplicitlyAnimatedWidgetState<T extends ImplicitlyAnimatedWidget> extends State<T> with SingleTickerProviderStateMixin<T> {
  /// The animation controller driving this widget's implicit animations.
  @protected
  AnimationController get controller => _controller;
  AnimationController _controller;

  /// The animation driving this widget's implicit animations.
  Animation<double> get animation => _animation;
  Animation<double> _animation;
  


  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      duration: widget.duration,
      debugLabel: kDebugMode ? widget.toStringShort() : null,
      vsync: this,
    );
    _controller.addStatusListener((AnimationStatus status) {
      switch (status) {
        case AnimationStatus.completed:
          if (widget.onEnd != null)
            widget.onEnd();
          break;
        case AnimationStatus.dismissed:
        case AnimationStatus.forward:
        case AnimationStatus.reverse:
      }
    });
    _updateCurve();
    _constructTweens();
    didUpdateTweens();
  }
  

///更新控件
  @override
  void didUpdateWidget(T oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.curve != oldWidget.curve)
      _updateCurve();
    _controller.duration = widget.duration;
    if (_constructTweens()) {
      forEachTween((Tween<dynamic> tween, dynamic targetValue, TweenConstructor<dynamic> constructor) {
        _updateTween(tween, targetValue);
        return tween;
      });
      _controller
        ..value = 0.0
        ..forward();
      didUpdateTweens();
    }
  }


//更新curve
  void _updateCurve() {
    if (widget.curve != null)
      _animation = CurvedAnimation(parent: _controller, curve: widget.curve);
    else
      _animation = _controller;
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

//是否需要启动动画,
  bool _shouldAnimateTween(Tween<dynamic> tween, dynamic targetValue) {
    return targetValue != (tween.end ?? tween.begin);
  }
  
//更新tween
  void _updateTween(Tween<dynamic> tween, dynamic targetValue) {
    if (tween == null)
      return;
    tween
      ..begin = tween.evaluate(_animation)
      ..end = targetValue;
  }

  //创建Tween 
  bool _constructTweens() {
    bool shouldStartAnimation = false;
    forEachTween((Tween<dynamic> tween, dynamic targetValue, TweenConstructor<dynamic> constructor) {
      if (targetValue != null) {
        tween ??= constructor(targetValue);
        if (_shouldAnimateTween(tween, targetValue))
          shouldStartAnimation = true;
      } else {
        tween = null;
      }
      return tween;
    });
    return shouldStartAnimation;
  }

  
  @protected
  void forEachTween(TweenVisitor<dynamic> visitor);


  @protected
  void didUpdateTweens() { }
}

这里值得分析的方法是initState

    _controller = AnimationController(
      duration: widget.duration,
      debugLabel: kDebugMode ? widget.toStringShort() : null,
      vsync: this,
    );
    _controller.addStatusListener((AnimationStatus status) {
      switch (status) {
        case AnimationStatus.completed:
          if (widget.onEnd != null)
            widget.onEnd();
          break;
        case AnimationStatus.dismissed:
        case AnimationStatus.forward:
        case AnimationStatus.reverse:
      }
    });
    _updateCurve();
    _constructTweens();
    didUpdateTweens();

先创建AnimationController ,添加状态监听,如果动画执行完毕,并且有onEnd 回调,则执行onEnd回调,更新Curve ,如果设置了Curve ,通过Curve 创建Animation,如果没设置,则将AnimationController 变为Animation<double>,_constructTweens 这个方法是最有意思的方法,

   //是否会启用动画
  bool _constructTweens() {
    // 默认不启动
    bool shouldStartAnimation = false;
    //初始化Tween ,tween的职责就是规范动画的初始状态和结束状态,
    //他的其实状态分为两种情况,
    //1.tween 为空的时候,使用constructor 创建 这个是用户自定义的,begin 和end 用户定义
    //2.tween不为空,更新tween,而他的开始值begin是 tween.transform(animation.value),end 是targetValue  也是用户定义的
    //这也就解释了ImplicitlyAnimatedWidgetState中_updateTween 这个方法的作用
    forEachTween((Tween<dynamic> tween, dynamic targetValue, TweenConstructor<dynamic> constructor) {
      if (targetValue != null) {
        tween ??= constructor(targetValue);
        if (_shouldAnimateTween(tween, targetValue))
          shouldStartAnimation = true;
      } else {
        tween = null;
      }
      return tween;
    });
    return shouldStartAnimation;
  }

改变背景色例子

class  TsmColorAnimatedDecorated  extends ImplicitlyAnimatedWidget  {
  final BoxDecoration decoration;
  final Widget child;

  TsmColorAnimatedDecorated({
    Key key,
    @required this.decoration,
    this.child,
    Curve curve = Curves.linear, //动画曲线
    @required Duration duration, // 正向动画执行时长
  }) : super(
    key: key,
    curve: curve,
    duration: duration,
  );

  @override
  ImplicitlyAnimatedWidgetState<ImplicitlyAnimatedWidget> createState()=> _TsmColorAnimatedDecoratedState();
}


class _TsmColorAnimatedDecoratedState extends ImplicitlyAnimatedWidgetState<TsmColorAnimatedDecorated>  {

  DecorationTween _tween;

  @override
  void initState() {
    super.initState();
  }



  @override
  Widget build(BuildContext context) {
    return DecoratedBox(
      decoration: _tween.transform(animation.value),
      child: widget.child,
    );
  }

  @override
  void forEachTween(visitor) {
    _tween = visitor(_tween, widget.decoration,
            (value) => DecorationTween(begin: value));
  }
}

使用了ImplicitlyAnimatedWidget 后代码就非常简单了,

Flutter 还定义了其他动画属性,方便大家使用

AnimatedPadding 在padding发生变化时会执行过渡动画到新状态

AnimatedPositioned 配合Stack一起使用,当定位状态发生变化时会执行过渡动画到新的状态。

AnimatedOpacity 在透明度opacity发生变化时执行过渡动画到新状态

AnimatedAlign 当alignment发生变化时会执行过渡动画到新的状态。

AnimatedContainer 当Container属性发生变化时会执行过渡动画到新的状态。

AnimatedDefaultTextStyle 当字体样式发生变化时,子组件中继承了该样式的文本组件会动态过渡到新样式。

我学习flutter的整个过程都记录在里面了
https://www.jianshu.com/c/36554cb4c804

最后附上demo 地址

https://github.com/tsm19911014/tsm_flutter

上一篇下一篇

猜你喜欢

热点阅读