Flutter-animation
- 1.Animation:抽象类 无法实例化所以必须使用子类 *监听动画值的改变 *监听动画状态的改变 *value 获取当前值 *status 获取当前状态
- 2.AnimationController继承自Animation *vsync同步信号,屏幕刷新率 一秒钟刷新60次(this-> with SingleTickerProviderStateMixin) *forward():向前执行动画 *reverse():反转执行动画
- 3.CurvedAnimation *设置执行的速率,即速度曲线 4.Tween:设置动画执行的value范围 *begin开始值 *end 结束值
主要代码
// 1.创建AnimationController
late AnimationController _controller;
late CurvedAnimation animation;
late Animation sizeAnim;
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 500),
// lowerBound: 50,
// upperBound: 150,
animationBehavior: AnimationBehavior.preserve
);
// 设置curved的值
animation = CurvedAnimation(parent: _controller, curve: Curves.linear);
//设置值得范围
sizeAnim = Tween(begin: 50.0,end: 150.0).animate(animation);
// 监听动画状态的改变
// 监听动画值的改变
_controller.addListener(() {
setState(() {
});
});
// 监听动画状态的改变
_controller.addStatusListener((status) {
if(status == AnimationStatus.completed){
_controller.reverse();
}else if(status == AnimationStatus.dismissed){
_controller.forward();
}
});
///销毁动画控制器
void dispose() {
_controller.dispose();
super.dispose();
}
记录一下整体代码:
import 'package:draw_guess_flutter/utils.dart';
import 'package:flutter/material.dart';
class MYWordBankPage extends StatefulWidget {
static const routerName = "/word_bank";
@override
State<MYWordBankPage> createState() => _MYWordBankPageState();
}
class _MYWordBankPageState extends State<MYWordBankPage> with SingleTickerProviderStateMixin {
// 1.创建AnimationController
late AnimationController _controller;
late CurvedAnimation animation;
late Animation sizeAnim;
@override
void initState() {
// TODO: implement initState
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 500),
// lowerBound: 50,
// upperBound: 150,
animationBehavior: AnimationBehavior.preserve
);
// 设置curved的值
animation = CurvedAnimation(parent: _controller, curve: Curves.linear);
sizeAnim = Tween(begin: 50.0,end: 150.0).animate(animation);
// 监听动画值的改变
_controller.addListener(() {
setState(() {
});
});
// 监听动画状态的改变
_controller.addStatusListener((status) {
if(status == AnimationStatus.completed){
_controller.reverse();
}else if(status == AnimationStatus.dismissed){
_controller.forward();
}
});
}
@override
Widget build(BuildContext context) {
// 只有收到同步信号的时候,才会进行帧绘制,在后台的时候不会绘制
// final controller = AnimationController(vsync: this);
// final animation = CurvedAnimation(parent: controller,curve: Curves.easeIn);
// final valueAnimation = Tween(begin: 100,end: 200).animate(animation);
return Scaffold(
appBar: buildMJYNavBar("我的词库"),
body: Center(
child: Icon(Icons.favorite,color: Colors.red,size: sizeAnim.value,),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
// _controller.forward();
if (_controller.isAnimating){
_controller.stop();
}else if(_controller.status == AnimationStatus.completed || _controller.status == AnimationStatus.dismissed){
_controller.forward();
} else{
if(_controller.status == AnimationStatus.forward){
_controller.forward();
}else{
_controller.reverse();
}
}
},
child: Icon(Icons.play_arrow),
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
以上代码缺点
- 每次写动画,都需要写一段代码
- setState -> build
优化方案一
将需要动画的部件用AnimatedWidget包裹,这样就不逼调用setState来使得不需要的部件也一直builder
class MJYAnimationIcon extends AnimatedWidget{
const MJYAnimationIcon(Animation anim, {Key? key}) : super(key: key, listenable: anim);
@override
Widget build(BuildContext context) {
Animation anim = listenable as Animation<double>;
return Icon(Icons.favorite,color: Colors.red,size: anim.value,);
}
缺点:
- 每次都需要创建一个类
- 如果构建的Widget有子类,那么子类依然会重复的builder
优化方案二
AnimationBuilder方案 类似Consumer
AnimatedBuilder(
animation: _controller,
builder: (ctx,child){
return Icon(Icons.favorite,color: Colors.red,size: sizeAnim.value,);
},
child: Text("不想要Builder的Widget"),
)
交织动画
- 需求
- 大小变化
- 颜色变化
- 透明度变化
- 旋转动画
// 设置curved的值
animation = CurvedAnimation(parent: _controller, curve: Curves.linear);
_sizeAnim = Tween(begin: 50.0,end: 150.0).animate(animation);
_colorAnim = ColorTween(begin: Colors.orange,end: Colors.purple).animate(animation);
_opacityAnim = Tween(begin: 1.0,end: 0.5).animate(animation);
_radiansAnim = Tween(begin: 0.0,end: 2 * pi).animate(animation);
AnimatedBuilder(
animation: _controller,
builder: (ctx,child){
return Opacity(
opacity: _opacityAnim.value,
child: Transform(
transform: Matrix4.rotationZ(_radiansAnim.value) ,
alignment: Alignment.center,
child: Container(
width: _sizeAnim.value,
height: _sizeAnim.value,
// transform: Matrix4.rotationZ(pi/4),
color: _colorAnim.value,
),
),
);
},
// child:
)
也就是多了一些tween
转场动画
//普通从右往左转场动画
Navigator.of(context).push(MaterialPageRoute(
builder: (ctx){
return MyPaintingsPage();
},
fullscreenDialog: true,
)
);
//modal动画
Navigator.of(context).push(
PageRouteBuilder(
transitionDuration: Duration(seconds: 3),
pageBuilder: (ctx, anim1, anim2) {
return FadeTransition(
opacity: anim1,
child: MyPaintingsPage(),
);
}),
);
Hero动画
Hero(
tag: myPaintings[index]["img"],
child: Container()
)
Hero(
tag: _imgUrl,
child: Image.network(_imgUrl))),
),
两个Hero中的tag值要相等
效果