大家好,我是 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 ,还是用直接继承 AnimatedWidget 或 juejin.cn/post/717196… 的方式比较好,并且 TweenAnimationBuilder 只能有一个 tween。
性能优化
TweenAnimationBuilder 的优化方式和 AnimatedBuilder 一样。已经说过了,不再赘述。