先上代碼:
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Material(child: ScaleAnimationRoute()),
),
);
}
//需要繼承TickerProvider,如果有多個AnimationController,則應(yīng)該使用TickerProviderStateMixin。
class _ScaleAnimationRouteState extends State<ScaleAnimationRoute> with SingleTickerProviderStateMixin {
Animation<double> animation;
AnimationController controller;
initState() {
super.initState();
controller = new AnimationController(
duration: const Duration(seconds: 3),
vsync: this,
);
//圖片寬高從0變到300
animation = new Tween(begin: 0.0, end: 300.0).animate(controller) //tag0
..addListener(() { //tag1
setState(() => {});
});
//啟動動畫(正向執(zhí)行)
controller.forward(); //tag2
}
@override
Widget build(BuildContext context) {
return new Center(
child: Image.asset(
"assets/banner1.png",
width: animation.value,
height: animation.value,
),
);
}
dispose() {
//路由銷毀時需要釋放動畫資源
controller.dispose();
super.dispose();
}
}
然后上圖:

圖片較大請放大看,然后開始分析:
- 從
tag0開始,這步生成了一個Tween,并設(shè)置了begin和end兩個屬性,然后調(diào)用animate方法,該方法內(nèi)部創(chuàng)建了一個_AnimatedEvaluation對象,這是一個Animation實例,然后返回設(shè)置給了引用animation,這步操作在_AnimatedEvaluation內(nèi)部保存了Tween.animate方法傳入的參數(shù)AnimationController和Tween自身 - 然后看
tag1,該步驟調(diào)用了_AnimatedEvaluation的addListener方法,_AnimatedEvaluation是從父類AnimationWithParentMixin繼承的該方法,在父類AnimationWithParentMixin里該方法的實現(xiàn)如下:
// keep these next five dartdocs in sync with the dartdocs in Animation<T>
/// Calls the listener every time the value of the animation changes.
///
/// Listeners can be removed with [removeListener].
void addListener(VoidCallback listener) => parent.addListener(listener);
其中parent是Tween.animate這步傳入的AnimationController,所以執(zhí)行的是AnimationController的addListener方法,所以監(jiān)聽的就是原始發(fā)送動畫數(shù)據(jù)的類實例,后面不管嵌套多少層動畫,原始數(shù)據(jù)都是從AnimationController這里獲取的值,范圍是0.0-1.0,然后看一下AnimationController這個類:
class AnimationController extends Animation<double>
with AnimationEagerListenerMixin, AnimationLocalListenersMixin, AnimationLocalStatusListenersMixin {
...
}
省略不相關(guān)代碼,只看繼承結(jié)構(gòu),AnimationController的addListener實現(xiàn)在父類AnimationLocalListenersMixin里面,所以tag1這步就把值改變時的監(jiān)聽方法保存到了AnimationController類
- 然后看
tag2,調(diào)用AnimationController的forward方法開始動畫后,方法內(nèi)部執(zhí)行_animateToInternal方法,然后animateToInternal內(nèi)部執(zhí)行notifyListeners和_checkStatusChanged遍歷值監(jiān)聽和狀態(tài)監(jiān)聽列表,然后我們的監(jiān)聽方法就被回調(diào)了,我們在回調(diào)里執(zhí)行了setState方法刷新界面,然后在_ScaleAnimationRouteState的build方法里調(diào)用animation.value獲取了變化的值,然后我們分析animation.value這個步驟:
3.1 因為animation是_AnimatedEvaluation的實例,所以我們看這個類的內(nèi)部value的方法實現(xiàn),該方法源碼如下:
@override
T get value => _evaluatable.evaluate(parent);
其中_evaluatable看tag0這步得知該實例是Tween,parent是AnimationController實例,
然后看Tween的內(nèi)部方法_evaluatable
/// The current value of this object for the given [Animation].
///
/// This function is implemented by deferring to [transform]. Subclasses that
/// want to provide custom behavior should override [transform], not
/// [evaluate].
///
/// See also:
///
/// * [transform], which is similar but takes a `t` value directly instead of
/// an [Animation].
/// * [animate], which creates an [Animation] out of this object, continually
/// applying [evaluate].
T evaluate(Animation<double> animation) => transform(animation.value);
Tween的evaluate方法內(nèi)部執(zhí)行transform(animation.value),其中animation是AnimationController,AnimationController的animation的value范圍是0.0-1.0,transform內(nèi)部是實際將0.0-1.0轉(zhuǎn)換成了對應(yīng)的值,也就是頁面調(diào)用animation(這個是我們的測試代碼的animation,是_AnimatedEvaluation實例,不要和transform方法里的搞混).value方法后獲得的計算好的值,可以看一下Tween的transform方法
@override
T transform(double t) {
if (t == 0.0)
return begin;
if (t == 1.0)
return end;
return lerp(t);
}
分析完了,這就是整個流程,復(fù)雜動畫可能會嵌套多個動畫效果,但是萬變不離其宗,原理都是一樣的,圖片里的[]實際就是(),但是這個starUML用了小括號后面就不能打字了,所以看的時候不要在這里迷糊就好,有問題請在下面留言,一起學(xué)習(xí)。