Flutter Animation(1)動畫的簡單使用
在動畫過程中,需要兩個部分:
- 第一個就是動畫控制類,它不需要知道在螢幕上顯示什麼。
- 第二個就是實際上的UI元素
1. 動畫控制類
動畫控制類有兩部分:
-
Animation
Animation
類物件是一個抽象類,支援泛型,我們常用的是Animation<double>
,當然這裡不僅僅是double,可以是任意一個物件。Animation物件本身和UI渲染沒有任何關係,而是用於生產動畫過程中的值,用這個值來控制動畫,也能獲取當前動畫的狀態(正在播放中,還是結束等),也能獲取動畫播放過程中的當前值。而且Animation
類有很多不同的子類,用於實現不同的動畫效果,我們下篇在將。 -
AnimationController
AnimationController
一方面是用來管理Animation
,比如動畫的開關,另一方面,AnimationController
和Animation
還有另外一種關係,就是AnimationController
是輸入,是X,它的範圍是從0.0到1.0的數字,經過Animation
裡定義的f(),對映到對應的Y值,
所以Animation
和AnimationController
是在動畫中比不可少的元素,而且這兩個一定是搭配使用的。看程式碼:
//定義的AnimationController,動畫時長2000ms AnimationController controller = AnimationController( vsync: this, duration: const Duration(milliseconds: 2000)); //Tween是Animation的子類,其實是定義了一種f(),Y的值是從50到200 //.animate(controller)是一定要呼叫的 Animation<double> animation = Tween(begin: 50.0, end: 200.0).animate(controller); //動畫控制,開始播放 controller.forward(); 複製程式碼
2 使用動畫
講完了動畫控制類,這個動畫控制類怎麼運用到UI元素上呢?
總共有三種方法:
- 原始方法
將Animation
的值直接用到widget的屬相上,用這種方法時,一定要記得Animation
裡要新增動畫的監聽addListener
方法,addListener
方法裡要呼叫setState(() {})
。
因為雖然Animation
的值變了,但如果不呼叫setState(() {})
的話,widget就不會重新繪製。
class AnimApp extends StatefulWidget { @override State<StatefulWidget> createState() { return _AnimAppState(); } } class _AnimAppState extends State<AnimApp> with SingleTickerProviderStateMixin { AnimationController controller; Animation<double> animation; @override void initState() { super.initState(); controller = AnimationController( vsync: this, duration: const Duration(milliseconds: 2000)); animation = Tween(begin: 50.0, end: 200.0).animate(controller) ..addListener(() { setState(() {}); }); controller.forward(); } @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Container( width: animation.value, height: animation.value, decoration: BoxDecoration(color: Colors.redAccent), ), )); } @override void dispose() { controller.dispose(); super.dispose(); } } 複製程式碼
-
AnimatedWidget
AnimatedWidget
是Flutter將動畫封裝成了Widget,更方便使用,而且不需要呼叫setState()
,AnimatedWidget
也有很多子類,這次先不介紹,先看它的普通使用,AnimatedWidget
需要一個Animation
的引數:
class AnimApp extends StatefulWidget { @override State<StatefulWidget> createState() { return _AnimAppState(); } } class _AnimAppState extends State<AnimApp> with SingleTickerProviderStateMixin { AnimationController controller; Animation<double> animation; @override void initState() { super.initState(); controller = AnimationController( vsync: this, duration: const Duration(milliseconds: 2000)); animation = Tween(begin: 50.0, end: 200.0).animate(controller); controller.repeat(); } @override Widget build(BuildContext context) { return Scaffold( body: AnimApp2(animation: animation,), ); } } class AnimApp2 extends AnimatedWidget { AnimApp2({Key key, Animation<double> animation}) : super(key: key, listenable: animation); @override Widget build(BuildContext context) { final Animation<double> animation = listenable; return Scaffold( body: Center( child: Container( width: animation.value, height: animation.value, decoration: BoxDecoration(color: Colors.redAccent), ), )); } } 複製程式碼
-
AnimatedBuilder
前面的
AnimatedWidget
,我要是每實現一個動畫就單獨抽出來一個class檔案來寫Widget,太複雜了,所以有了AnimatedBuilder
,AnimatedBuilder
可以更方便的為Widget新增動畫,看程式碼:
class AnimApp extends StatefulWidget { @override State<StatefulWidget> createState() { return _AnimAppState(); } } class _AnimAppState extends State<AnimApp> with SingleTickerProviderStateMixin { AnimationController controller; Animation<double> animation; @override void initState() { super.initState(); controller = AnimationController( vsync: this, duration: const Duration(milliseconds: 2000)); animation = Tween(begin: 50.0, end: 200.0).animate(controller); controller.repeat(); } @override Widget build(BuildContext context) { return Scaffold( body: AnimatedBuilder( animation: animation, builder: (context, child) { return Center( child: Container( width: animation.value, height: animation.value, decoration: BoxDecoration(color: Colors.redAccent), ), ); }, ), ); } } 複製程式碼