flutter動(dòng)畫
1.動(dòng)畫原理:在一段時(shí)間內(nèi)快速的多次改變UI外觀,由于人眼會(huì)產(chǎn)生視覺暫留所以最終看到的就是一個(gè)連續(xù)的動(dòng)畫艾栋。
UI的一次改變稱為一個(gè)動(dòng)畫幀派阱,對(duì)應(yīng)一次屏幕刷新跋涣。
FPS:幀率宜咒,每秒的動(dòng)畫幀數(shù)惠赫。
flutter動(dòng)畫分為兩類:
- 補(bǔ)間動(dòng)畫
- 物理動(dòng)畫
常見動(dòng)畫模式:
- list、grid中的動(dòng)畫:例如一些元素的添加或者刪除故黑。
- 轉(zhuǎn)場(chǎng)動(dòng)畫
- 交錯(cuò)動(dòng)畫
基本的動(dòng)畫概念與類:
Animation
是一個(gè)抽象類,主要的功能是保存動(dòng)畫的值和狀態(tài)庭砍。常用的一個(gè)Animation類是Animation< double >,是一個(gè)在一段時(shí)間內(nèi)依次生成一個(gè)區(qū)間之間的值的類场晶,可以是線性或者曲線或者其他。
可以生成除double之外的其他類型值怠缸,如:Animation< Color > 或 Animation< Size >诗轻。
AnimationController
是一個(gè)動(dòng)畫控制器,控制動(dòng)畫的播放狀態(tài)揭北,在屏幕刷新的每一幀扳炬,就會(huì)生成一個(gè)新的值。
包含動(dòng)畫的啟動(dòng)forward()搔体、停止stop() 恨樟、反向播放 reverse()等方法,在給定的時(shí)間段內(nèi)線性的生成從0.0到1.0(默認(rèn)區(qū)間)的數(shù)字疚俱。
- 使用Listeners和StatusListeners監(jiān)聽動(dòng)畫狀態(tài)改變劝术。
AnimationController controller = AnimationController(
duration: Duration(milliseconds: 2000), vsync: this);
Curve
curve:描述動(dòng)畫的曲線過程。
curvedAnimation:指定動(dòng)畫的曲線。
final CurvedAnimation curve =
new CurvedAnimation(parent: controller, curve: Curves.easeIn);
常用Curve:
- linear:勻速的
- decelerate:勻減速
- ease:開始減速后減速
- easeIn:開始慢后快
- easeOut:開始快后慢
- easeInOut:開始慢加速再減速
Tween
繼承自Animatable< T >养晋,表示的就是一個(gè) Animation 對(duì)象的取值范圍衬吆,只需要設(shè)置開始和結(jié)束的邊界值(值也支持泛型)。 它唯一的工作就是定義輸入范圍到輸出范圍的映射绳泉。
例如逊抡,Tween可能會(huì)生成從紅到藍(lán)之間的色值,或者從0到255零酪。
final Tween colorTween =
new ColorTween(begin: Colors.transparent, end: Colors.black54);
Tween.animate:返回一個(gè)Animation冒嫡。
映射過程:
1). Tween.animation通過傳入 aniamtionController 獲得一個(gè)_AnimatedEvaluation 類型的 animation 對(duì)象(基類為 Animation), 并且將 aniamtionController 和 Tween 對(duì)象傳入了 _AnimatedEvaluation 對(duì)象蛾娶。
Animation<T> animate(Animation<double> parent) {
return _AnimatedEvaluation<T>(parent, this);
}
2). animation.value方法即是調(diào)用 _evaluatable.evaluate(parent)方法灯谣, 而 _evaluatable 和 parent 分別為 Tween 對(duì)象和 AnimationController 對(duì)象。
T get value => _evaluatable.evaluate(parent);
....
class _AnimatedEvaluation<T> extends Animation<T> with AnimationWithParentMixin<double> {
_AnimatedEvaluation(this.parent, this._evaluatable);
3). 這里的 animation 其實(shí)就是前面的 AnimationController 對(duì)象蛔琅, transform 方法里面的 animation.value則就是 AnimationController 線性生成的 0.0~1.0 直接的值胎许。 在 lerp 方法里面我們可以看到這個(gè) 0.0~1.0 的值被映射到了 begin 和 end 范圍內(nèi)了。
T evaluate(Animation<double> animation) => transform(animation.value);
T transform(double t) {
if (t == 0.0)
return begin;
if (t == 1.0)
return end;
return lerp(t);
}
T lerp(double t) {
assert(begin != null);
assert(end != null);
return begin + (end - begin) * t;
}
vsync
接收一個(gè)TickerProvider類型的對(duì)象罗售,它的主要職責(zé)是創(chuàng)建Ticker辜窑。
防止屏幕外動(dòng)畫消耗資源。
流程圖:
[圖片上傳失敗...(image-115b94-1636441483468)]
總結(jié):
過程:
- TickerProvider 會(huì)創(chuàng)建一個(gè) Ticker寨躁, 并將_tick(TickerCallback 類型)回調(diào)方法綁定到了 這個(gè) Ticker穆碎, 這樣 AnimationController 就將回調(diào)方法 _tick 和 Ticker 綁定了。
- Ticker 會(huì)在 start 函數(shù)內(nèi)將_tick 被綁定到 SchedulerBinding 的幀回調(diào)方法內(nèi)职恳。
- SchedulerBinding 則是在構(gòu)造方法中將自己的 _handleBeginFrame 函數(shù)和 window 的 onBeginFrame 綁定了回調(diào)所禀。 這個(gè)回調(diào)會(huì)在屏幕需要準(zhǔn)備顯示幀之前回調(diào)。
- 在 AnimationController 的回調(diào)當(dāng)中放钦, 計(jì)算當(dāng)前的的_value 值色徘, 更新 Animation Status 的狀態(tài), 判斷是否動(dòng)畫已經(jīng)結(jié)束操禀。 最后通過 notifyListeners 和_checkStatusChanged 方法通知給監(jiān)聽器 value 和 AnimationStatus 的變化褂策。
回調(diào):
ui.window.onBeginFrame = handleBeginFrame;
ui.window.onDrawFrame = handleDrawFrame;
- window調(diào)用SchedulerBinding的_handleBeginFrame方法
- SchedulerBinding調(diào)用Ticker的_tick方法
- Ticker調(diào)用 AnimationController的_tick的方法,
- animationContoller通知監(jiān)聽器
- 而監(jiān)聽器調(diào)用widget的setStatus方法來調(diào)用build更新
- build使用了Animation對(duì)象當(dāng)前的值來繪制動(dòng)畫幀
用AnimatedWidget簡(jiǎn)化
不使用addListener()和setState()來給widget添加動(dòng)畫颓屑。
使用AnimatedWidget斤寂,將widget分離出來,創(chuàng)建一個(gè)可重用動(dòng)畫的widget揪惦,AnimatedWidget中會(huì)自動(dòng)調(diào)用addListener()和setState()
class AnimatedImage extends AnimatedWidget {
AnimatedImage({Key key, Animation<double> animation})
: super(key: key, listenable: animation);
Widget build(BuildContext context) {
final Animation<double> animation = listenable;
return new Center(
child: Image.asset("imgs/avatar.png",
width: animation.value,
height: animation.value
),
);
}
}
常用控件
AnimatedModalBarrier遍搞、DecoratedBoxTransition、FadeTransition丹擎、PositionedTransition尾抑、RelativePositionedTransition歇父、RotationTransition、ScaleTransition再愈、SizeTransition榜苫、SlideTransition
AnimatedBuilder重構(gòu)
如何渲染過渡,把渲染過程也抽象出來:
AnimatedBuilder的示例包括: BottomSheet翎冲、 PopupMenu垂睬、ProgressIndicator、RefreshIndicator抗悍、Scaffold驹饺、SnackBar、TabBar缴渊。
轉(zhuǎn)場(chǎng)動(dòng)畫
MaterialPageRoute:平臺(tái)風(fēng)格一致的路由切換動(dòng)畫
CupertinoPageRoute:左右切換風(fēng)格
Navigator.push(context, CupertinoPageRoute(
builder: (context)=>PageB(),
));
自定義:PageRouteBuilder
交織動(dòng)畫
1.要?jiǎng)?chuàng)建交織動(dòng)畫赏壹,需要使用多個(gè)動(dòng)畫對(duì)象(Animation)。
2.一個(gè)AnimationController控制所有的動(dòng)畫對(duì)象衔沼。
3.給每一個(gè)動(dòng)畫對(duì)象指定時(shí)間間隔(Interval)
AnimatedSwitcher
可以同時(shí)對(duì)其新蝌借、舊子元素添加顯示、隱藏動(dòng)畫.
當(dāng)AnimatedSwitcher的child發(fā)生變化時(shí)(類型或Key不同)指蚁,舊child會(huì)執(zhí)行隱藏動(dòng)畫菩佑,新child會(huì)執(zhí)行執(zhí)行顯示動(dòng)畫。
希望大家支持一下凝化,感謝
https://itunes.apple.com/cn/app/id1581903089