【动画 widget】Flutter TweenAnimationBuilder

339 阅读2分钟

大家好,我是 17,今天的每日 widget 为大家介绍 TweenAnimationBuilder。

Flutter TweenAnimationBuilder 继承自 ImplicitlyAnimatedWidget,它的作用是生成一个有动画功能的 StatefulWidget widget 作为复杂 widget 的一部分。

源码分析

构造函数

 const TweenAnimationBuilder({
    super.key,
    required this.tween,
    required super.duration,
    super.curve,
    required this.builder,
    super.onEnd,
    this.child,
  })

ImplicitlyAnimatedWidget 相比,增加了 tween 和 build。 tween 只有一个,不像 ImplicitlyAnimatedWidget 那样可以操作 多个 tween。

 if (_currentTween!.begin != _currentTween!.end) {
      controller.forward();
 }

ImplicitlyAnimatedWidget 不同的是,一旦发现 tween 的开始结束不一样,就立即执行动画,不用等到通过改变属性来触发。

  Widget build(BuildContext context) {
    return widget.builder(context, _currentTween!.evaluate(animation), widget.child);
  }

widget.builder 通过一个函数生成 widget,给我们可以自定义 widget 内容的能力。

 @override
  void forEachTween(TweenVisitor<dynamic> visitor) {
    assert(
      widget.tween.end != null,
      'Tween provided to TweenAnimationBuilder must have non-null Tween.end value.',
    );
    _currentTween = visitor(_currentTween, widget.tween.end, (dynamic value) {
      assert(false);
      throw StateError('Constructor will never be called because null is never provided as current tween.');
    }) as Tween<T>?;
  }

TweenAnimationBuilder 为我们复写了 forEachTween。 参数 tween.end 不能为空,实际上 ,tween.begin 也不能为空,在 initState 阶段,已经给 tween.begin 赋值。这样一来,tween 的值就是完整的。和 ImplicitlyAnimatedWidget 出场时没有动画相比, 只要 tween.begin!=tween.end 就会有出场动画。

tween.end 不为空。所以就不需要 tween 的构造函数了,visitor 中的构造函数永远不会执行。

使用 TweenAnimationBuilder

使用 TweenAnimationBuilder 要比 使用 ImplicitlyAnimatedWidget 简单的多,不需要自定义类。

还是拿上次 AnimatedWidget 正方形 的例子,看看用 TweenAnimationBuilder 如何写。

class MyAnimation extends StatefulWidget {
  const MyAnimation({super.key});

  @override
  State<MyAnimation> createState() => _MyAnimationState();
}

class _MyAnimationState extends State<MyAnimation> {
  double targetValue = 100;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            body: Center(
                child: TweenAnimationBuilder<double>(
      tween: Tween<double>(begin: 0, end: targetValue),
      builder: (context, value, child) {
        return GestureDetector(
          onTap: () {
              setState(() {
              targetValue = targetValue == 100 ? 50 : 100;
            });
          },
          child: Container(color: Colors.blue[200],width: value,height: value,),
        );
      },
      duration:const Duration(seconds: 1),
      
    ))));
  }
}

效果上,动画并不能循环播放。只能是出场的时候执行一次,受到点击的时候再执行一次

和用 ImplicitlyAnimatedWidget 的实现方式相比,代码确实简洁很多。TweenAnimationBuilder 让动画 widget 以内嵌的方式嵌入到其它 widget 当中,省去了自定类。

但是 TweenAnimationBuilder 也是有他的不足的,如果要多次复用动画 Widget ,还是用直接继承 AnimatedWidgetjuejin.cn/post/717196… 的方式比较好,并且 TweenAnimationBuilder 只能有一个 tween。

性能优化

TweenAnimationBuilder 的优化方式和 AnimatedBuilder 一样。已经说过了,不再赘述。