Flutter Animation动画开发之——AnimatedWidget
程序员文章站
2022-03-09 20:21:14
...
在Flutter Animation动画开发之——最简单的动画入门这篇文章中我们介绍了创建一个动画的基本流程,其中每创建一个动画都要通过addListener来监听动画的每一帧,然后调用setState来刷新UI。我们今天要介绍的AnimatedWidget内部帮我们实现了这一步骤,其内部会监听动画然后更新UI。
AnimatedWidget示例
首先我们将需要执行动画的控件单独抽出来,继承AnimatedWidget自定义成一个动画控件,构造方法中的animation参数从外部接收一个Animation动画,记得传给父类构造方法的listenable参数,将动画的监听和更新UI交由父类处理
class MyAnimatedWidget extends AnimatedWidget {
MyAnimatedWidget({Key key, Animation<double> animation})
: super(key: key, listenable: animation);
Widget build(BuildContext context) {
final Animation<double> animation = listenable;
return Center(
// 这里显示一个绿色方块,随着动画的执行会不断变大
child: Container(
color: Colors.red,
width: animation.value,
height: animation.value,
),
);
}
}
然后在布局中使用该自定义的动画控件,传入动画参数,该动画无需再通过addListener监听变化来更新UI
class AnimationRoute extends StatefulWidget {
@override
AnimationRouteState createState() => AnimationRouteState();
}
class AnimationRouteState extends State<AnimationRoute> with SingleTickerProviderStateMixin {
Animation<double> animation;
AnimationController controller;
initState() {
super.initState();
// Controller设置动画时长
// vsync设置一个TickerProvider,当前State 混合了SingleTickerProviderStateMixin就是一个TickerProvider
controller = AnimationController(
duration: Duration(seconds: 5),
vsync: this //
);
animation=CurvedAnimation(parent: controller, curve: Curves.bounceInOut);
// Tween设置动画的区间值,animate()方法传入一个Animation,AnimationController继承Animation
// 这里无需再通过addListener监听动画来更新UI
animation = new Tween(begin: 50.0, end: 250.0).animate(animation);
//启动动画(正向执行)
controller.forward();
}
@override
Widget build(BuildContext context) {
return MyAnimatedWidget(animation: animation);
}
@override
void dispose() {
// 释放资源
controller.dispose();
super.dispose();
}
}
AnimatedWidget源码解析
代码如下所示,主要包括AnimatedWidget和_AnimatedState这两个类,代码比较简单,我们主要看listenable这个变量,AnimatedWidget的核心就是通过监听listenable来更新UI的,listenable其实就是我们传入的动画,下面做简要说明
我们先看下AnimatedWidget的源码
- listenable不能为空,所以自定义的子类必须将动画传给listenable
- AnimatedWidget是一个有状态的控件,其状态由_AnimatedState管理
再看下_AnimatedState的源码
- 在initState()方法中调用listenable.addListener(_handleChange)监听动画
- 在_handleChange()方法中处理动画监听,调用setState()方法通知更新UI
- 在build()方法中返回widget.build(),也就是自定义AnimatedWidget中重写build方法中自定义的UI
- 在dispose()方法中调用listenable.removeListener(_handleChange)移除动画监听
abstract class AnimatedWidget extends StatefulWidget {
/// Creates a widget that rebuilds when the given listenable changes.
///
/// The [listenable] argument is required.
const AnimatedWidget({
Key key,
@required this.listenable,
}) : assert(listenable != null),
super(key: key);
/// The [Listenable] to which this widget is listening.
///
/// Commonly an [Animation] or a [ChangeNotifier].
final Listenable listenable;
/// Override this method to build widgets that depend on the state of the
/// listenable (e.g., the current value of the animation).
@protected
Widget build(BuildContext context);
/// Subclasses typically do not override this method.
@override
_AnimatedState createState() => _AnimatedState();
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<Listenable>('animation', listenable));
}
}
class _AnimatedState extends State<AnimatedWidget> {
@override
void initState() {
super.initState();
widget.listenable.addListener(_handleChange);
}
@override
void didUpdateWidget(AnimatedWidget oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.listenable != oldWidget.listenable) {
oldWidget.listenable.removeListener(_handleChange);
widget.listenable.addListener(_handleChange);
}
}
@override
void dispose() {
widget.listenable.removeListener(_handleChange);
super.dispose();
}
void _handleChange() {
setState(() {
// The listenable's state is our build state, and it changed already.
});
}
@override
Widget build(BuildContext context) => widget.build(context);
}
上一篇: 配置打包文件路径出错怎样解决
下一篇: 微信小程序开发-基础目录创建