您好,登錄后才能下訂單哦!
這篇文章主要講解了“Flutter Component動畫的顯和隱怎么實現”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Flutter Component動畫的顯和隱怎么實現”吧!
Flutter中包含大量的動畫組件和自定義動畫方式,所以,在合適的場景下選擇合適的動畫實現方式就成了決定代碼質量好壞的一個重要因素。
Flutter中的動畫從廣義上來講可以分為兩類,一類是基于繪制的動畫(Drawing-based animations),另一類是基于代碼的動畫(Code-based animations)。
首先,我們需要區分是使用CustomPainter,或者是使用Lottie、Flare這種第三方庫,這一類的動畫很容易區分——如果你第一感覺,這個動畫我做不了,那它大概率就是了。
接下來,就是區分是使用「顯示動畫」還是「隱式動畫」。
簡單的說,它們的區別如下:
隱式動畫:不用循環播放、不用隨時中斷、不用多個動畫協同,它實現的是一種狀態到另一種狀態的改變
顯示動畫:需要自己控制動畫過程
最后,就是看現有組件是否滿足需求,如果不行,那么就需要自定義相應的動畫。
這就是整個動畫決策樹的執行過程。它們的開發難度,如下所示。
下面我們就具體來分析下不同的動畫實現。本文首先介紹顯示動畫和隱式動畫。
在Flutter中,很多常用組件都有其自帶的隱式動畫版本,例如下圖所示的這些組件。
這些組件在Flutter中被稱之為隱式動畫Widget,下面以AnimatedContainer為例,來看下Implicit Animations的使用。
隱式動畫有一個特點,那就是它們都是以「Animated」開頭。
AnimatedContainer的使用非常簡單,甚至和普通的Container沒有太大的區別,代碼如下所示。
AnimatedContainer( margin: EdgeInsets.only(top: 20), width: size, height: size, decoration: BoxDecoration( color: color, borderRadius: BorderRadius.circular(radius), ), curve: Curves.easeIn, duration: Duration(milliseconds: 300), ),
當通過setState函數改變AnimatedContainer中的屬性時,AnimatedContainer會經過一段動畫效果,然后再完成相應的改變。在隱式動畫中,你依然可以定義Curve和Duration等參數,但是你無法控制動畫,即動畫的執行和結束,是由屬性改變來驅動的。
Implicit Animations可以非常方便的使Widget具有動畫效果而不需要寫很多額外的動畫代碼,結合FutureBuilder或者StreamBuilder,甚至不用寫setState,下面這個例子就演示了如何將Implicit Animations和FutureBuilder結合起來使用,代碼如下所示。
FutureBuilder( future: future, builder: (context, snapshot) { var width = .0; switch (snapshot.connectionState) { case ConnectionState.none: case ConnectionState.waiting: case ConnectionState.active: width = .0; break; case ConnectionState.done: width = 100.0; break; } return AnimatedContainer( width: width, duration: Duration(seconds: 1), curve: Curves.easeIn, child: Image.asset('images/logo.png'), ); }, ),
通過FutureBuilder的各種狀態回調,就可以設置不同的Widget,并在FutureBuilder完成并顯示正常的Widget時,產生一個動畫效果,而不是非常生硬的出現。
TweenAnimationBuilder是自定義隱式動畫的方式,借助它,你可以給一個指定的Widget作用一個動畫效果,一個簡單的示例代碼如下所示。
TweenAnimationBuilder( tween: Tween<double>(begin: 0, end: 48), onEnd: (){} duration: Duration(seconds: 1), builder: (BuildContext context, double size, Widget child) { return IconButton( iconSize: size, color: Colors.blue, icon: child, ); }, child: Icon(Icons.aspect_ratio), )
借助TweenAnimationBuilder,就可以將一個指定的Tween作用于builder中的Widget,builder中的第二個參數,就是Tween所指定的參數的類型,通過TweenAnimationBuilder,就可以在Widget參數變化的時候產生動畫效果。
TweenAnimationBuilder的builder中如果有不變的Child Widget,可以放在TweenAnimationBuilder的child屬性中,因為builder在產生動畫時會重建,所有不變的Widget,都可以放在TweenAnimationBuilder的child中,再通過builder的第三個參數來傳遞這個Widget,以避免重建。
通常我們在開發中,會借助Transform來完成動畫效果,在builder中,根據Tween返回的數值,使用不同的Transform來修改動畫狀態。
TweenAnimationBuilder中的begin,只在第一次使用,后面更新時,只看end的值,例如10-30,修改end為50,實際變化是30-50。如果不傳begin,那么默認和end相等。
與隱式動畫不同,顯示動畫給了開發者對動畫過程的完全掌控,開發者可以根據自己的需要來控制動畫,Flutter中內置了很多顯示動畫,如下所示。
顯示動畫也有一個很明顯的特點,那就是它們都以「Transition」結尾。
以RotationTransition為例,下面來演示下如何使用Flutter中的顯示動畫。
顯示動畫是通過AnimationController來進行驅動的,所以,使用顯示動畫的第一步,就是需要創建AnimationController。有了AnimationController之后,就可以通過控制AnimationController的狀態來控制動畫的驅動過程,整個代碼如下所示。
AnimationController controller; @override void initState() { super.initState(); controller = AnimationController(vsync: this, duration: Duration(seconds: 2))..repeat(); } @override void dispose() { controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Center( child: GestureDetector( onTap: () { if (controller.isAnimating) { controller.stop(); } else { controller.repeat(); } }, child: RotationTransition( turns: controller, child: FlutterLogo( size: 100, ), ), ), ); }
與隱式動畫相比,顯式動畫通過AnimationController來獲取動畫的行進狀態和參數,從而讓調用者能夠控制動畫的行進過程。
顯式動畫可以實現隱式動畫的所有功能,但是比隱式動畫多了管理動畫生命周期的工作
當Flutter內置顯示動畫不能滿足開發者的需求時,Flutter提供了AnimatedBuilder和AnimatedWidget來讓開發者對顯示動畫進行自定義。
前面提到的都是Flutter中使用動畫的最基本方式,但實際上,Flutter提供了很多關于動畫的封裝組件,可以讓開發者更加方便的使用動畫,這就是AnimatedWidget。AnimatedWidget也有很多實現類,如圖所示。
AnimatedWidget是實現自定義顯示動畫的另一種方式,它可以將一些動畫的邏輯以Widget的形式封裝起來,從而讓build函數中的代碼邏輯更加清晰,下面是AnimatedWidget的示例代碼。
@override Widget build(BuildContext context) { return Stack( children: <Widget>[ AnimWidget(animation: controller), Center(child: FlutterLogo(size: 100)), ], ); } class AnimWidget extends AnimatedWidget { const AnimWidget({ Key? key, required Animation<double> animation, }) : super(key: key, listenable: animation); @override Widget build(BuildContext context) { Animation<double> animation = listenable as Animation<double>; return Container( decoration: BoxDecoration( gradient: RadialGradient( colors: const [Colors.red, Colors.transparent], stops: [0, animation.value], ), ), ); } }
那么這種方式和之前直接使用AnimationController和Tween有什么區別呢?細心的讀者可能已經發現了,AnimatedWidget不需要自己去監聽動畫的回調,也不需要通過setState來刷新動畫,這些操作,AnimatedWidget已經封裝好了,這就是AnimatedWidget的作用。
AnimatedBuilder是一個特殊的AnimatedWidget,它可以直接指定一個動畫作用于Widget上,而不需要重新創建一個自定義的AnimatedWidget,它可以幫助開發者處理動畫的監聽,當一個Widget Tree中有一些需要動畫的Widget,也有一些不需要動畫的Widget時,用AnimatedBuilder可以很方便的避免非動畫Widget的重繪,所以說,AnimatedBuilder可以更加方便的給一個Widget增加動畫效果。
AnimatedBuilder與其它的顯示動畫一樣,也是通過AnimationController驅動的,借助AnimatedBuilder,開發者可以根據需要,自己創建Animation并控制它,下面的代碼演示了如何通過控制RadialGradient的stop屬性來控制RadialGradient的顯示大小,從而形成動畫效果,代碼如下所示。
@override Widget build(BuildContext context) { return AnimatedBuilder( animation: controller, builder: (context, widget) { return Stack( children: <Widget>[ Container( decoration: BoxDecoration( gradient: RadialGradient( colors: [Colors.red, Colors.transparent], stops: [0, controller.value], ), ), ), Center(child: FlutterLogo(size: 100)) ], ); }, ); }
上面的代碼演示了如何使用AnimatedBuilder,實際上非常簡單,與使用內置的顯示動畫的過程基本一致。
在使用AnimatedBuilder的過程中,需要盡可能多的將需要動畫的部分和不需要動畫的部分區分開來,這樣可以避免多余的重繪,從而提高動畫性能,例如上面的代碼,可以將FlutterLogo和Stack放置在最外層,這樣只需要讓RadialGradient產生動畫就可以了,代碼如下所示。
@override Widget build(BuildContext context) { return Stack( children: <Widget>[ AnimatedBuilder( animation: controller, builder: (context, widget) { return Container( decoration: BoxDecoration( gradient: RadialGradient( colors: [Colors.red, Colors.transparent], stops: [0, controller.value], ), ), ); }, ), Center(child: FlutterLogo(size: 100)) ], ); }
AnimatedBuilder接收了一個animation,在child中,可以直接使用這個animation的值,其它都和普通的AnimatedWidget類似。
實際上,AnimatedBuilder就是AnimatedWidget的子類,所以在本質上,這兩種實現自定義顯示動畫的方式想相同的,開發者可以根據自己的喜好來選擇相應的方式來創建自己的顯示動畫。
AnimateWidget負責組件的抽離,可以看出組件中雜糅了動畫邏輯。而AnimatedBuilder恰好相反,它不在意組件是什么,只是將動畫抽離達到復用簡單。
Flutter中的顯示動畫和隱式動畫,幾乎可以解決大部分我們平時在開發中遇到的動畫場景,借助動畫選擇決策樹,我們可以對動畫的選擇了如指掌,剩下的工作,就是對動畫進行拆解,分而治之。
感謝各位的閱讀,以上就是“Flutter Component動畫的顯和隱怎么實現”的內容了,經過本文的學習后,相信大家對Flutter Component動畫的顯和隱怎么實現這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。