动画的基本使用代码示例:
class AnimationDemo extends StatefulWidget {
@override
_AnimationDemoState createState() => _AnimationDemoState();
}
class _AnimationDemoState extends State
with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation _curvedAnimation;
Animation _sizeAnimation;
@override
void initState() {
super.initState();
// 创建AnimationController
_controller = AnimationController(
vsync: this,
duration: Duration(seconds: 2),
);
// 设置Curve的值
_curvedAnimation = CurvedAnimation(
parent: _controller,
curve: Curves.linear,
);
// Tween
_sizeAnimation = Tween(begin: 50.0, end: 150.0).animate(_curvedAnimation);
// 监听动画值改变
_controller.addListener(() {
setState(() {});
});
// 监听动画状态改变
_controller.addStatusListener((status) {
if (status == AnimationStatus.completed) {
_controller.reverse();
} else if (status == AnimationStatus.dismissed) {
_controller.forward();
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Animation Demo'),
),
body: Center(
child: Icon(
Icons.favorite,
color: Colors.red,
size: _sizeAnimation.value,
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.play_arrow),
onPressed: () {
if (_controller.isAnimating) {
_controller.stop();
print(_controller.status);
} else if (_controller.status == AnimationStatus.forward) {
_controller.forward();
} else if (_controller.status == AnimationStatus.reverse) {
_controller.reverse();
} else {
_controller.forward();
}
},
),
);
}
@override
void dispose() {
// 释放动画资源
_controller.dispose();
super.dispose();
}
}
使用AnimatedWidget简化
上面的示例通过addListener()
和setState()
来更新UI,这一步其实是通用的,如果每个动画中都加这么一句是比较繁琐的,还会造成不必要的widget重建。AnimatedWidget
类封装了调用setState()
的细节,并允许我们将widget
分离出来。优化后的代码:
class _AnimatedIcon extends AnimatedWidget {
_AnimatedIcon(Animation animation) : super(listenable: animation);
@override
Widget build(BuildContext context) {
final Animation animation = listenable;
return Icon(
Icons.favorite,
color: Colors.red,
size: animation.value,
);
}
}
class _AnimationDemoState extends State
with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation _curvedAnimation;
Animation _sizeAnimation;
@override
void initState() {
super.initState();
// 创建AnimationController
_controller = AnimationController(
vsync: this,
duration: Duration(seconds: 2),
);
// 设置Curve的值
_curvedAnimation = CurvedAnimation(
parent: _controller,
curve: Curves.linear,
);
// Tween
_sizeAnimation = Tween(begin: 50.0, end: 150.0).animate(_curvedAnimation);
// 监听动画状态改变
_controller.addStatusListener((status) {
if (status == AnimationStatus.completed) {
_controller.reverse();
} else if (status == AnimationStatus.dismissed) {
_controller.forward();
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Animation Demo'),
),
body: Center(
child: _AnimatedIcon(_sizeAnimation),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.play_arrow),
onPressed: () {
if (_controller.isAnimating) {
_controller.stop();
print(_controller.status);
} else if (_controller.status == AnimationStatus.forward) {
_controller.forward();
} else if (_controller.status == AnimationStatus.reverse) {
_controller.reverse();
} else {
_controller.forward();
}
},
),
);
}
@override
void dispose() {
// 释放动画资源
_controller.dispose();
super.dispose();
}
}
用AnimatedBuilder重构
用AnimatedWidget
可以从动画中分离出widget,而动画的渲染过程仍然在AnimatedWidget
中,如果再添加一个widget
另一个动画效果,那么需要再实现一个AnimatedWidget
,这样不是很优雅,如果能把渲染过程也抽象出来,那就会好很多,而AnimatedBuilder
正是将渲染逻辑分离出来,代码示例:
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Animation Demo'),
),
body: Center(
child: AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return Icon(
Icons.favorite,
color: Colors.red,
size: _sizeAnimation.value,
);
},
),
),
}
通过AnimatedBuilder
可以封装常见的过渡效果来复用动画,代码示例:
class GrowTransition extends StatelessWidget {
GrowTransition({this.child, this.animation});
final Widget child;
final Animation animation;
Widget build(BuildContext context) {
return Center(
child: new AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget child) {
return Container(
height: animation.value,
width: animation.value,
child: child,
);
},
child: child,
),
);
}
}
Flutter中正是通过这种方式封装了很多动画,如:FadeTransition
、ScaleTransition
、SizeTransition
等。
代码传送门