對于前端來說,我感覺最大的魅力就是在于動畫效果了;最初入坑前端就是想做出炫酷的動畫,其實可以學習AE什么的,當時不懂,就入了前端程序員的坑。當然用代碼實現(xiàn)出炫酷的動畫效果,更會讓自己充滿成就感。

1. 動畫簡介
在一段時間內(nèi),快速地多次改變UI外觀,由于人眼會產(chǎn)生視覺殘留,所以最后會看到連續(xù)的動畫。對于人眼來說,動畫幀率超過16FPS,就比較流暢了,超過32FPS就會非常的細膩平滑,而超過32FPS,人眼基本上就感受不到差別了。由于動畫的每一幀都是要改變UI輸出,所以在一個時間段內(nèi)連續(xù)的改變UI輸出是比較耗資源的,對設(shè)備的軟硬件系統(tǒng)要求都較高,所以在UI系統(tǒng)中,動畫的平均幀率是重要的性能指標,而在Flutter中,理想情況下是可以實現(xiàn)60FPS的,這和原生應用能達到的幀率是基本是持平的?!?《flutter實戰(zhàn).動畫簡介》
2. flutter動畫
在web前端,我們實現(xiàn)動畫可以通過css過渡元素,定義css關(guān)鍵幀,js等定義動畫函數(shù)等方式去實現(xiàn),那么flutter如何去實現(xiàn)動畫效果呢?如果是想簡單的實現(xiàn)動畫,可以選擇flutter內(nèi)置的一些動畫Widget,flutter已經(jīng)封裝好了:AnimatedPadding,AnimatedPositioned,AnimatedOpacity,AnimatedAlign,AnimatedContainer,AnimatedDefaultTextStyle,這些拿來即用,但是這些不能隨心控制;想要自己自定義實現(xiàn)動畫的話那就需要以下的幾個步驟:
- 創(chuàng)建一個動畫控制器
AnimationController - 添加一個描述動畫的過程
Curve,返回的是一個Animation - 添加
tween,控制動畫的執(zhí)行范圍,需要執(zhí)行animate方法,返回Animation
AnimationController: 創(chuàng)建動畫控制器,默認動畫執(zhí)行范圍是[0,1],如果需要改變的話,需要用到tween
3. 開始制作簡單的動畫
動畫效果:一個正方形,先變大,然后變顏色,然后再變小,還原顏色
前提準備,新建好項目,新建class AnimationDemo
class AnimationDemo extends StatefulWidget {
@override
State<StatefulWidget> createState() {
// TODO: implement createState
return AnimationDemoState();
}
}
class AnimationDemostate extends State<AnimationDemo> with SingleTickerProviderStateMixin {
// SingleTickerProviderStateMixin 性能有關(guān),需要執(zhí)行Ticker
// 動畫控制器需要傳這個參數(shù),效果是在頁面不可見的區(qū)域,動畫不會執(zhí)行,避免消耗資源。
}
3.1 定義動畫和控制器變量
class AnimationDemostate extends State<AnimationDemo> with SingleTickerProviderStateMixin {
// SingleTickerProviderStateMixin 性能有關(guān),需要執(zhí)行Ticker
// 動畫控制器需要傳這個參數(shù),效果是在頁面不可見的區(qū)域,動畫不會執(zhí)行,避免消耗資源。
Animation animation;
AnimationController _animationController;
}
3.2 初始化動畫變量
我們先嘗試讓紅色的正方形在3秒內(nèi)從10的寬高變道300的寬高,以下代碼中做了以下幾步
- 先創(chuàng)建了一個動畫控制器,
duration動畫的持續(xù)時間,vsync這個就是當前的State - 創(chuàng)建了一個動畫函數(shù)
CurvedAnimation它的是一個Animation - 創(chuàng)建
Tween,begin:10.0,end: 300.0,這個就是在3秒之內(nèi)會生成10~300的值
new Tween它是繼承Animatable<T>,而不是跟CurvedAnimation一樣繼承Animation;那我們創(chuàng)建的Animatable如何與Animation形成映射呢?答案是執(zhí)行animate方法把Animation傳進去,就形成了新的Animation,我們就可以在Widget中愉快使用了它了。 - 執(zhí)行動畫
_animationController.forward();
class AnimationDemostate extends State<AnimationDemo> with SingleTickerProviderStateMixin{
···
@override
void initState() {
// TODO: implement initState
_animationController = new AnimationController(
duration: Duration(seconds: 3),
vsync: this,
);
animation = new CurvedAnimation(
parent: _animationController,
curve: Curves.ease
);
// Tween begin,end 就是大小變化的區(qū)間
animationSize = new Tween(begin: 10.0, end: 300.0).animate(animation)
..addListener((){
setState(() {
});
});
_animationController.forward();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
···
new Container(
width: animationSize.value,
height: animationSize.value,
decoration: BoxDecoration(
color: Colors.red,
),
)
···
)
}
···
}
經(jīng)過上面步驟之后我們來看下效果:

皆大歡喜,我們已經(jīng)成功了第一步!能有動畫的效果了,我們繼續(xù)深入后續(xù)的步驟
3.3 讓紅色正方形變大的過程中變成其他顏色
這種相當于是關(guān)鍵幀的意思,就是先變大,在變大的過程中某個時間開始變顏色;在web中我們知道css中有@keyframe可是設(shè)置關(guān)鍵幀,來進行交織動畫,flutter中我們?nèi)绾螌崿F(xiàn)呢?
在3.2步驟中我們創(chuàng)建過一個動畫曲線CurvedAnimation,curve傳的是flutter內(nèi)置的動畫函數(shù)Curves.ease,在vscode中打出Curves后編輯器會有提示所有的內(nèi)置的函數(shù);我們要打關(guān)鍵幀的話,關(guān)鍵在于此curve,這里需要用到Interval(start, end),這個Interval通過start和end我們就能知道了,它表示的是一段時間間隔,可以傳入curve參數(shù)。
了解上面的內(nèi)容之后,我們思路應該清爽了,那繼續(xù)深入
3.3.1 使正方形變大的過程中由紅色變成藍色
class xxx extends xxx with xxx {
// 定義變量
Animation animationColor;
// 初始化變量
void initState() {
// TODO: implement initState
_animationController = new AnimationController(
duration: Duration(seconds: 3),
vsync: this,
);
animation = new CurvedAnimation(
parent: _animationController,
curve: new Interval(0, 0.5) // 這里執(zhí)行間隔 是3秒中0~50%的時間執(zhí)行正方形變大,默認動畫
);
animationSize = new Tween(begin: 10.0, end: 300.0).animate(animation)
..addListener((){
setState(() {
});
});
animation = new CurvedAnimation(
parent: _animationController,
curve: new Interval(0.5, 1.0, curve: Curves.easeIn) // 50%~100%執(zhí)行變顏色,并且動畫是easeIn
);
animationColor = new ColorTween(begin: Colors.white, end: Colors.blue).animate(animation)
..addListener((){
setState(() {
});
});
}
}
通過上面步驟之后
我們來看看最終的的效果:

最后想實現(xiàn)循環(huán)往復的效果
需要在動畫監(jiān)聽狀態(tài)中去改變動畫的方向就可以了
方法如下:
animation.addStatusListener((status){
if (status == AnimationStatus.completed) {
_animationController.reverse();
} else if (status == AnimationStatus.dismissed) {
_animationController.forward();
}
});
來看看效果:

總結(jié)
這邊主要是對flutter動畫的一個簡單的入門,按照上面步驟一步步的去實現(xiàn)flutter的動畫,應該就會對flutter動畫有了一定的了解了,具體深入的了解可以看官方文檔和其他資料的書籍,如果文中有講述不到位的地方,或者有錯誤的地方,也請大佬們多多指教,康桑密達!