大家好,我是 17,今天的每日 widget 为大家介绍 AnimatedWidget。
Flutter AnimatedWidget 是一个 StatefulWidget,它的作用是当 listenalbe 变化的时候,rebuild Widget 让 UI 也随着变化。
源码分析
构造函数
const AnimatedWidget({
super.key,
required this.listenable,
});
}
AnimatedWidget 是一个抽象类,所以即使他是一个 widget,也不能直接用。 参数里面并没有 child,所有的 UI 都在 build 方法里完成。
class _AnimatedState extends State<AnimatedWidget> {
@override
void initState() {
super.initState();
widget.listenable.addListener(_handleChange);
}
... 省略 didUpdateWidget,dispose
void _handleChange() {
setState(() {
// The listenable's state is our build state, and it changed already.
});
}
@override
Widget build(BuildContext context) => widget.build(context);
}
逻辑在 state 里面。_AnimatedState 就做了一件事:当 listenable(通常是 Animation 对象)变化的时候,rebuild Widget。
通过代码可以知道,AnimatedWidget 帮我们把监听的工作抽象出来,让我们再写动画的不时候省去了监听的代码。这也是抽象类的意义,把公共的部分抽离出来,减少子类的工作量。
使用 AnimatedWidget
使用 AnimatedWidget 很简单的,只需要给他一个 listenable 对象。
举一个简单的例子,不断放大的正方形。
class AnimatedBox extends AnimatedWidget {
const AnimatedBox({Key? key, required Animation<double> listenalbe})
: super(key: key, listenable: listenalbe);
Animation get animation => listenable as Animation<double>;
@override
Widget build(BuildContext context) {
return Container(
width: animation.value * 100,
height: animation.value * 100,
color: Colors.blue[200],
);
}
}
class _MyAnimationState extends State<MyAnimation>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
@override
void initState() {
_controller =
AnimationController(vsync: this, duration: const Duration(seconds: 1))
..repeat();
super.initState();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: AnimatedBox(
listenalbe: _controller.view,
))));
}
}
要注意的是 _controller 需要及时 dispose。使用 AnimatedWidget ,让我们不光省去了监听的事,还省去了 State 类。代码省去了不少,但是使用起来还是有点麻烦,还得创建 Controller,使用 ImplicitlyAnimatedWidget 可以解决这个问题。
性能优化
每当做动画效果的时候,都要认真考虑性能的问题,因为动画的刷新频率太高了,稍有不慎就会造成卡顿。有两种办法可以优化性能
我们先加一个 MyWidget,方便测试
class MyWidget extends StatelessWidget {
const MyWidget({super.key});
@override
Widget build(BuildContext context) {
print('build');
return Container(
color: Colors.blue,
width: 50,
height: 50,
);
}
}
使用 const 关键字
class AnimatedBox extends AnimatedWidget {
const AnimatedBox({Key? key, required Animation<double> listenalbe})
: super(key: key, listenable: listenalbe);
Animation get animation => listenable as Animation<double>;
@override
Widget build(BuildContext context) {
return Container(
width: animation.value * 100,
height: animation.value * 100,
color: Colors.blue[200],
// 新增加的代码
child:const MyWdiget()
);
}
}
加上 const 关键字后,MyWdiget 只 build 一次。
去掉 const 关键字,再看下效果。
通过 child 传进来。
class AnimatedBox extends AnimatedWidget {
const AnimatedBox({Key? key, required Animation<double> listenalbe,required this.child})
: super(key: key, listenable: listenalbe);
final Widget child;
Animation get animation => listenable as Animation<double>;
@override
Widget build(BuildContext context) {
return Container(
width: animation.value * 100,
height: animation.value * 100,
color: Colors.blue[200],
child: child
);
}
}
AnimatedBox(
child: MyWidget(),
listenalbe: _controller,
);
把 MyWidget() 通过 child 的方式传到 AnimatedBox 里面,即使不加 const 关键字,MyWidget 也只 build 一次。