animation
-
Animation: 抽象类 监听动画值的改变 监听动画状态的改变 value status
-
AnimationController 继承自Animation vsync:同步构造信号, 需要是statefulWidget 混入 SingleTickerProviderStateMixin forward(): reverse():
-
CurvedAnimation 设置动画执行的速率
-
Tween: 设置动画执行的value的范围
1. 直接使用 setState 来更新动画
// 动画执行需要调用setState,即需要是StatefulWidget
class MyAnimations extends StatefulWidget {
MyAnimations({super.key});
@override
State<MyAnimations> createState() => _MyAnimationsState();
}
// state 需要混入 SingleTickerProviderStateMixin
class _MyAnimationsState extends State<MyAnimations> with SingleTickerProviderStateMixin{
late AnimationController _controller; // 动画控制器
late Animation _animation; // 动画执行函数
late Animation _animation1; // 动画执行的数值变化
@override
void initState() {
super.initState();
// 控制器的创建vsync:固定传this,duration 动画执行时长。
_controller = AnimationController(vsync: this, duration: Duration(seconds: 1));
// 动画执行时间函数.parent:传控制器。curve: 时间函数
_animation = CurvedAnimation(parent: _controller, curve: Curves.linear );
// Tween动画执行时数值的变化,
_animation1 = Tween(begin: 50.0,end: 150.0).animate(_controller);
// 动画监听,执行时是使用setState 更新builder
_controller.addListener(() {
setState(() {
});
});
// 监听动画执行的状态。
_controller.addStatusListener((AnimationStatus 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('animations'),),
// 需要执行动画的widget:icon的size,变大变小
body: Center(child: Icon(Icons.favorite, color: Colors.red, size: _animation1.value,),),
floatingActionButton: FloatingActionButton(
onPressed: () {
// 开始执行动画
_controller.forward();
},
child: Icon(Icons.play_lesson),
),
);
}
}
2. AnimatedBuilder实现动画
不需要去写监听更新widget。这样也就不会一直调用builder函数。减少开销 AnimatedBuilder的参数:animation:对应的动画控制器 builder: (context,child){} 函数, 函数返回需要使用动画的widget。 child: 执行动画的widget
class MyAnimations extends StatefulWidget {
MyAnimations({super.key});
@override
State<MyAnimations> createState() => _MyAnimationsState();
}
class _MyAnimationsState extends State<MyAnimations> with SingleTickerProviderStateMixin{
late AnimationController _controller;
late Animation _animation;
late Animation _size;
late Animation _color;
late Animation _opvalue;
late Animation _rovalue;
@override
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: Duration(seconds: 1));
_animation = CurvedAnimation(parent: _controller, curve: Curves.linear );
_size = Tween(begin: 10.0,end: 100.0).animate(_controller);
_rovalue = Tween(begin: 0.0,end: 2*pi).animate(_controller);
_color = ColorTween(begin: Colors.red,end: Colors.purple).animate(_controller);
_opvalue = Tween(begin: 0.0,end: 1.0).animate(_controller);
// _controller.addListener(() {
// setState(() {
// });
// });
_controller.addStatusListener((AnimationStatus 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('animations'),),
body: Center(
child: AnimatedBuilder(
animation: _controller,
builder: (context,child){
return Transform(
transform: Matrix4.rotationZ(_rovalue.value),
alignment: Alignment.center,
child: Opacity(
opacity: _opvalue.value ,
child: Container(
width: _size.value,
height: _size.value,
color: _color.value,
),
),
);
}
)
),
floatingActionButton: FloatingActionButton(
onPressed: () {
_controller.forward();
},
child: Icon(Icons.play_lesson),
),
);
}
}
hero 动画 (飞入飞出的动画)
Hero参数: 必传参数 :tag 是区别执行hero动画的标志。 child: widget。
class MyHeroPage extends StatefulWidget {
const MyHeroPage({super.key});
@override
State<MyHeroPage> createState() => _MyHeroPageState();
}
class _MyHeroPageState extends State<MyHeroPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('hero page'),
),
body: GridView.count(
crossAxisCount: 2,
childAspectRatio: 16 / 9,
mainAxisSpacing: 10,
crossAxisSpacing: 10,
children: List.generate(20, (index) {
final images = "https://picsum.photos/200/300?random=$index";
return Hero(
// tag 使用图片的地址
tag: images,
child: GestureDetector(
onTap: () {
Navigator.push(
context,
// 使用自定义的页面跳转动动画:transitionDuration 动画执行时间,pageBuilder函数携带context 和 两个动画参数,FadeTransition 渐入动画
PageRouteBuilder(
// transitionDuration: Duration(seconds: 1),
pageBuilder:
(context, animation, secondaryAnimation) {
return FadeTransition(
opacity: animation,
child: MyImgagView(
imageurl: images,
),
);
}));
},
child: Image.network(
"https://picsum.photos/200/300?random=$index",
fit: BoxFit.cover,
),
));
}),
));
}
}
class MyImgagView extends StatelessWidget {
final imageurl;
const MyImgagView({super.key, this.imageurl});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: double.infinity,
height: double.infinity,
color: Colors.black,
child: Hero(
// 使用传过来的图片地址作为tag, hero 动画需要两个hero。 然后根据tag 作为标识
tag: imageurl,
child: Center(
child: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Image.network(
imageurl,
fit: BoxFit.cover,
),
),
))));
}
}
结果:点击图片,图片会在当前位置飞出放大。显示在黑色背景下