一:使用 AnimationController 实现缩放动画
class ScaleAnimationRoute extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _ScaleAnimationRouteState();
}
}
// 需要继承 TickerProvider , 如果有多个 AnimationController,则应该使用 TickerProviderStateMixin
class _ScaleAnimationRouteState extends State<ScaleAnimationRoute>
with SingleTickerProviderStateMixin {
Animation<double> animation;
@override
void initState() {
super.initState();
// 这个家伙独立就可以完成整个动画
controller = new AnimationController(
vsync: this,
duration: const Duration(seconds: 1),
lowerBound: 10.0,
upperBound: 400.0)
..addListener(() {
setState(() => {});
});
// 启动动画(正向执行)
controller.forward();
}
@override
Widget build(BuildContext context) {
return Image.asset(
"images/avatar.jpg",
width: controller.value,
height: controller.value,
);
}
@override
void dispose() {
// 需要进行释放,以免内存泄露
controller.dispose();
super.dispose();
}
}
二:使用 AnimationController + CurvedAnimation + Tween 实现缩放动画
// 需要继承 TickerProvider , 如果有多个 AnimationController,则应该使用 TickerProviderStateMixin
class _ScaleAnimationRouteState extends State<ScaleAnimationRoute>
with SingleTickerProviderStateMixin {
AnimationController controller;
CurvedAnimation curvedAnimation;
Animation<double> animation;
@override
void initState() {
super.initState();
controller = new AnimationController(
duration: const Duration(seconds: 3), vsync: this);
curvedAnimation =
CurvedAnimation(parent: controller, curve: Curves.decelerate);
// 图片宽高从 0 变到 300
animation = new Tween(begin: 0.0, end: 300.0).animate(curvedAnimation)
..addListener(() {
setState(() => {});
});
// 启动动画(正向执行)
controller.forward();
}
@override
Widget build(BuildContext context) {
return Image.asset(
"images/avatar.jpg",
width: animation.value,
height: animation.value,
);
}
@override
void dispose() {
// 需要进行释放,以免内存泄露
controller.dispose();
super.dispose();
}
}
三:使用 AnimatedBuilder 重构
class ScaleAnimationRoute extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _ScaleAnimationRouteState();
}
}
// 需要继承 TickerProvider , 如果有多个 AnimationController,则应该使用 TickerProviderStateMixin
class _ScaleAnimationRouteState extends State<ScaleAnimationRoute>
with SingleTickerProviderStateMixin {
AnimationController controller;
CurvedAnimation curvedAnimation;
Animation<double> animation;
@override
void initState() {
super.initState();
controller = new AnimationController(
duration: const Duration(seconds: 3), vsync: this);
curvedAnimation =
CurvedAnimation(parent: controller, curve: Curves.decelerate);
// 图片宽高从 0 变到 300
animation = new Tween(begin: 0.0, end: 300.0).animate(curvedAnimation);
// 启动动画(正向执行)
controller.forward();
}
@override
Widget build(BuildContext context) {
return GrowTransition(
child: Image.asset("images/333.jpg"),
animation: animation,
);
}
@override
void dispose() {
// 需要进行释放,以免内存泄露
controller.dispose();
super.dispose();
}
}
class GrowTransition extends StatelessWidget {
GrowTransition({this.child, this.animation});
final Widget child;
final Animation<double> animation;
@override
Widget build(BuildContext context) {
return new Center(
child: new AnimatedBuilder(animation: animation, child: child ,builder: (BuildContext context, Widget child){
return new Container(
height: animation.value,
width: animation.value,
child: child,
);
}),
);
}
}
优点
- 不用显式的去添加帧监听器,然后再调用
setState()
了,这个好处和AnimatedWidget
是一样的。 - 动画构建的范围缩小了,如果没有 Builder,setState()将会在父组件上下文中调用,这将会导致父组件的 build 方法重新调用;而有了 builder 之后,只会导致动画 widget 自身的 build 重新调用,避免不必要的 rebuild。
- 通过 AnimatedBuilder 可以封装常见的过渡效果来复用动画。
四:让动画永动起来。
initState() {
super.initState();
controller = new AnimationController(
duration: const Duration(seconds: 1), vsync: this);
//图片宽高从0变到300
animation = new Tween(begin: 0.0, end: 300.0).animate(controller);
animation.addStatusListener((status) {
if (status == AnimationStatus.completed) {
//动画停在结束状态时反向执行动画
controller.reverse();
} else if (status == AnimationStatus.dismissed) {
//动画停在初始状态时执行动画(正向)
controller.forward();
}
});
//启动动画(正向)
controller.forward();
}
循环动画,这种动画效果,我们只需要监听动画状态改变即可。
网友评论