本篇簡單介紹下在Flutter中動畫的實現(xiàn)以及示例平移、縮放、旋轉(zhuǎn)和alpha動畫。
1.動畫相關(guān)知識介紹
在Flutter中Widget動畫的組成有下面這些:
-
Animation:動畫庫中的一個核心類,它生成指導(dǎo)動畫的值; -
CurvedAnimation:將動畫過程抽象為一個非線性曲線; -
AnimationController:用來管理管理動畫,常用的方法有forward():啟動動畫;reverse({double from}:倒放動畫;reset():重置動畫,將其設(shè)置到動畫的開始位置;stop({ bool canceled = true }):停止動畫。 -
Tween:AnimationController對象的范圍從0.0到1.0。如果您需要不同的范圍或不同的數(shù)據(jù)類型,則可以使用Tween來配置動畫以生成不同的范圍或數(shù)據(jù)類型的值。
在開發(fā)的過程中我們用AnimatedWidget與AnimatedBuilder可以更簡練的方便我們對Widget進行動畫的操作:
-
AnimatedWidget:使用它可以簡化我們對動畫的使用,在不使用AnimatedWidget的情況下需要手動調(diào)用動畫的addListener(),并在回調(diào)中添加setState()才能看到動畫效果,而使用AnimatedWidget我們就可以簡化這一操作。 -
AnimatedBuilder: 用于構(gòu)建動畫的通用Widget,可以理解為是拆分動畫的一個工具類,借助它我們可以將動畫和widget進行分離,更加的好管理。
2.平移動畫
我們直接用SlideTransition來一個平移動畫示例:
import 'package:flutter/material.dart';
class BoxMoveAnimation extends StatefulWidget {
BoxMoveAnimation({Key key, this.title}) : super(key: key);
final String title;
@override
_BoxMoveAnimationState createState() => _BoxMoveAnimationState();
}
class _BoxMoveAnimationState extends State<BoxMoveAnimation> with TickerProviderStateMixin {
AnimationController controller;
Animation<Offset> animation;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body: Container(
//SlideTransition 用于執(zhí)行平移動畫
child: SlideTransition(
position: animation,
//將要執(zhí)行動畫的子view
child: Container(
width: 200,
height: 200,
color: Colors.red,
),
),
),
);
}
@override
void initState() {
// TODO: implement initState
super.initState();
controller =
AnimationController(duration: Duration(milliseconds: 2000), vsync: this);
controller.addStatusListener((status) {
if (status == AnimationStatus.completed) {
//AnimationStatus.completed 動畫在結(jié)束時停止的狀態(tài)
debugPrint('完成');
controller.reverse();
} else if (status == AnimationStatus.dismissed) {
//AnimationStatus.dismissed 表示動畫在開始時就停止的狀態(tài)
debugPrint('消失');
controller.forward();
// controller.dispose();
}
});
animation =
Tween(begin: Offset.zero, end: Offset(1.0, 0.0)).animate(controller);
//開始執(zhí)行動畫
controller.forward();
}
}
看一下運行效果:

可以看到我們利用
SlideTransition來做平移動畫還是非常方便的,直接將animation設(shè)置為position屬性就可以了。
3.縮放動畫
直接用ScaleTransition來一個縮放動畫的示例:
class BoxScaleAnimation extends StatefulWidget {
BoxScaleAnimation({Key key, this.title}) : super(key: key);
final String title;
@override
_BoxScaleAnimationState createState() => _BoxScaleAnimationState();
}
class _BoxScaleAnimationState extends State<BoxScaleAnimation> with TickerProviderStateMixin {
AnimationController controller;
@override
void initState() {
// TODO: implement initState
super.initState();
controller =
AnimationController(duration: const Duration(seconds: 2), vsync: this);
controller.addStatusListener((status) {
if (status == AnimationStatus.completed) {
print("completed");
controller.reverse();
} else if (status == AnimationStatus.dismissed) {
print("dismissed");
controller.forward();
} else if (status == AnimationStatus.forward) {
print("forward");
} else if (status == AnimationStatus.reverse) {
print("reverse");
}
});
controller.forward();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body:Center(
child: ScaleTransition(
alignment: Alignment.center,
scale: controller,
child: Container(
width: 200,
height: 200,
color: Colors.blue,
),
),
),
);
}
@override
void dispose() {
super.dispose();
controller.dispose();
}
}
看一下運行效果:

4.旋轉(zhuǎn)動畫
用RotationTransition來一個縮放動畫的示例:
class BoxRotationAnimation extends StatefulWidget {
BoxRotationAnimation({Key key, this.title}) : super(key: key);
final String title;
@override
_BoxRotationAnimationState createState() => _BoxRotationAnimationState();
}
class _BoxRotationAnimationState extends State<BoxRotationAnimation> with TickerProviderStateMixin {
AnimationController controller;
Animation animation;
@override
void initState() {
// TODO: implement initState
super.initState();
controller =
AnimationController(duration: const Duration(seconds: 3), vsync: this);
animation =
Tween(begin: 0.0, end: 0.25).animate(controller);
controller.addStatusListener((status) {
if (status == AnimationStatus.completed) {
print("completed");
controller.reverse();
} else if (status == AnimationStatus.dismissed) {
print("dismissed");
controller.forward();
} else if (status == AnimationStatus.forward) {
print("forward");
} else if (status == AnimationStatus.reverse) {
print("reverse");
}
});
controller.forward();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body:Center(
child: RotationTransition(
alignment: Alignment.center,
turns: animation,
child: Container(
width: 160,
height: 160,
color: Colors.green,
child: Center(
child: Text('Box'),
),
),
),
),
);
}
@override
void dispose() {
super.dispose();
controller.dispose();
}
}
看一下運行效果:

旋轉(zhuǎn)的動畫中我們對動畫的旋轉(zhuǎn)的值進行了限制,默認的情況下旋轉(zhuǎn)角度是360°,代碼限制到了0.25也就是90°。就像前面說的
Animation用來生成指導(dǎo)動畫的值。
5.Opacity動畫
用FadeTransition來一個Opacity動畫的示例:
class BoxOpacityAnimation extends StatefulWidget {
BoxOpacityAnimation({Key key, this.title}) : super(key: key);
final String title;
@override
_BoxOpacityAnimationState createState() => _BoxOpacityAnimationState();
}
class _BoxOpacityAnimationState extends State<BoxOpacityAnimation> with TickerProviderStateMixin {
AnimationController controller;
Animation animation;
@override
void initState() {
// TODO: implement initState
super.initState();
controller =
AnimationController(duration: const Duration(seconds: 2), vsync: this);
animation =
Tween(begin: 0.0, end: 1.0).animate(controller);
controller.addStatusListener((status) {
if (status == AnimationStatus.completed) {
print("completed");
controller.reverse();
} else if (status == AnimationStatus.dismissed) {
print("dismissed");
controller.forward();
} else if (status == AnimationStatus.forward) {
print("forward");
} else if (status == AnimationStatus.reverse) {
print("reverse");
}
});
controller.forward();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.title)),
body:Center(
child: FadeTransition(
opacity: animation,
child: Container(
width: 160,
height: 160,
color: Colors.green,
child: Center(
child: Text('Box'),
),
),
),
),
);
}
@override
void dispose() {
super.dispose();
controller.dispose();
}
}
看一下運行效果:

通過以上示例,我們會發(fā)現(xiàn)官方給我們封裝的
AnimatedWidget的確非常的方便,能夠滿足我們一般的動畫需求,這里必須列一下Flutter中文網(wǎng)的動畫介紹,里面的Hero 動畫是一個非常好的示例,系統(tǒng)封裝的動畫Widget非常好用,可以自己去看看,Animatedbuilder的使用可以點擊這里直接看到,文中所有的代碼都可以在Github:BoxJ/Flutter-daydayup中下載,本篇代碼的文件夾是boxdemo_006,歡迎一起交流!