AnimatedWidget 基本类可以从动画代码中区分出核心 widget 代码。 AnimatedWidget 不需要保持 State 对象来 hold 动画。AnimatedWidget 帮助类(代替 addListener() 和 setState())创建动画 widget。
利用 AnimatedWidget 创建一个可以运行重复使用动画的 widget。
Flutter API 中的 AnimatedWidget:AnimatedBuilder, RotationTransition, ScaleTransition, SizeTransition, SlideTransition。
一个从矩形的宽高收缩
class MyAnimationWidget extends StatefulWidget {
const MyAnimationWidget({Key? key}) : super(key: key);
@override
_MyAnimationWidgetState createState() => _MyAnimationWidgetState();
}
class _MyAnimationWidgetState extends State<MyAnimationWidget>
with SingleTickerProviderStateMixin {
late AnimationController controller;
late Animation<double> animation;
@override
initState() {
super.initState();
controller = AnimationController(
duration: const Duration(milliseconds: 2000), vsync: this);
animation = Tween(begin: 0.0, end: 300.0).animate(controller);
controller.forward();
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: AnimationLogo(animation),
),
);
}
}
class AnimationLogo extends AnimatedWidget {
const AnimatedLogo({super.key, required Animation<double> animation})
: super(listenable: animation);
@override
Widget build(BuildContext context) {
final animation = listenable as Animation<double>;
return Center(
child: Container(
height: animation.value,
width: animation.value,
color: Colors.red,
),
);
}
}
AnimatedBuilder 知道如何渲染过渡效果
但 AnimatedBuilder 不会渲染 widget,也不会控制动画对象。
使用 AnimatedBuilder 描述一个动画是其他 widget 构建方法的一部分。如果只是单纯需要用可重复使用的动画定义一个 widget。
Flutter API 中 AnimatedBuilders:BottomSheet, ExpansionTile, PopupMenu, ProgressIndicator, RefreshIndicator, Scaffold, SnackBar, TabBar, TextField。
AnimatedWidget 示例代码中有个问题,就是改变动画需要改变渲染 logo 的widget。较好的解决办法是,将任务区分到不同类里:
a. 渲染 logo
b. 定义动画对象
c. 渲染过渡效果
AnimatedBuilder 动画示例
class _MyAnimationWidgetState extends State<MyAnimationWidget>
with SingleTickerProviderStateMixin {
late AnimationController controller;
late Animation<double> animation;
@override
initState() {
super.initState();
controller = AnimationController(
duration: const Duration(milliseconds: 2000), vsync: this);
animation = Tween(begin: 0.0, end: 300.0).animate(controller);
controller.forward();
}
@override
void dispose() {
controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: AnimationLogo(
animation,
child: LogoWidget(),
),
),
);
}
}
class LogoWidget extends StatelessWidget {
const LogoWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Center(
child: Container(
color: Colors.red,
),
);
}
}
class AnimationLogo extends StatelessWidget {
final Animation<double> animation;
final Widget child;
AnimationLogo(this.animation, {Key? key, required this.child});
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget? child) {
return SizedBox(
height: animation.value,
width: animation.value,
child: child,
);
},
child: child,
);
}
}
从上面代码可以看出widget和动画效果分开了,所以AnimatedBuilder进一步将AnimatedWidget 进行分离,这样就可以让动画效果进行复用了,非常不错的。