Flutter Animation动画开发之——AnimatedBuilder
程序员文章站
2022-03-09 20:18:44
...
源码分析
在Flutter Animation动画开发之——AnimatedWidget这篇文章中我们介绍了AnimatedWidget的使用方法。今天要介绍的AnimatedBuilder其实是继承AnimatedWidget,所以功能与其类似,也是无需手动调用addListener监听动画然后调用setState来更新UI。其源码很简单,先做个简单介绍:
- AnimatedBuilder继承AnimatedWidget
- animation参数不为空,传入一个动画,然后传给AnimatedWidget的listenable,listenable在AnimatedWidget已介绍过,用于监听该动画,然后通知更新UI,就无需手动调用addListener监听动画然后调用setState更新UI
- build参数不为空,传入一个build方法自定义动画起作用的控件
- child是可选参数,有传的话,可以用于包裹在build方法返回的控件里面,作用可以详细看源码里child参数的说明,child是动画不起作用的子控件树,child由外部传入的话在每次动画更新重绘的时候就无需重绘该子控件树,可以提高效率
class AnimatedBuilder extends AnimatedWidget {
/// Creates an animated builder.
///
/// The [animation] and [builder] arguments must not be null.
const AnimatedBuilder({
Key key,
@required Listenable animation,
@required this.builder,
this.child,
}) : assert(animation != null),
assert(builder != null),
super(key: key, listenable: animation);
/// Called every time the animation changes value.
final TransitionBuilder builder;
/// The child widget to pass to the [builder].
///
/// If a [builder] callback's return value contains a subtree that does not
/// depend on the animation, it's more efficient to build that subtree once
/// instead of rebuilding it on every animation tick.
///
/// If the pre-built subtree is passed as the [child] parameter, the
/// [AnimatedBuilder] will pass it back to the [builder] function so that it
/// can be incorporated into the build.
///
/// Using this pre-built child is entirely optional, but can improve
/// performance significantly in some cases and is therefore a good practice.
final Widget child;
@override
Widget build(BuildContext context) {
return builder(context, child);
}
}
示例代码
下面的代码演示了一个绿色方块,中间显示“野猿新一”四个字,方块的宽高从100变成200
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 //
);
// Tween设置动画的区间值,animate()方法传入一个Animation,AnimationController继承Animation
animation = new Tween(begin: 100.0, end: 200.0).animate(controller);
//启动动画(正向执行)
controller.forward();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: animation,
builder: (BuildContext ctx, Widget child) {
return Center(
child: Container(
color: Colors.green,
alignment: Alignment.center,
width: animation.value,
height: animation.value,
child: Text('野猿新一',
style: TextStyle(
color: Colors.black,
fontSize: 18.0,
),
),
),
);
}
);
}
@override
void dispose() {
// 释放资源
controller.dispose();
super.dispose();
}
}
方块中的Text('野猿新一')其实是不被动画影响的,因为动画只影响方块的宽高,但是上面代码的写法中当动画每次更新还是会重绘该Text。上面源码解析中我们提到AnimatedBuilder中还有一个child参数,可以传入不被动画影响的子控件树,我们可以把该Text传给child,这样改控件只会绘制一次,可以提高效率。
build方法修改如下,将Text('野猿新一')传给AnimatedBuilder的child参数,然后Container的child参数直接引用AnimatedBuilder的child
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: animation,
child: Text('野猿新一',
style: TextStyle(
color: Colors.black,
fontSize: 18.0,
),
),
builder: (BuildContext ctx, Widget child) {
return Center(
child: Container(
color: Colors.green,
alignment: Alignment.center,
width: animation.value,
height: animation.value,
child: child,
),
);
}
);
}
推荐阅读
-
Android开发之图形图像与动画(三)Animation效果的XML实现
-
Android开发之图形图像与动画(四)AnimationListener简介
-
Android开发之图形图像与动画(二)Animation实现图像的渐变/缩放/位移/旋转
-
Android开发之图形图像与动画(一)Paint和Canvas类学习
-
Android开发之图形图像与动画(五)LayoutAnimationController详解
-
Android开发之背景动画简单实现方法
-
css3的动画特效之动画序列(animation)
-
python游戏开发之视频转彩色字符动画
-
python 之 前端开发( jQuery事件、动画效果、.each()、 .data())
-
基于CSS3特效之动画:animation的应用