Flutter使用AnimatedBuilder實(shí)現(xiàn)動(dòng)效復(fù)用
前言
我們之前講述了動(dòng)畫構(gòu)建的兩種方式,Animation
和 AnimationWidget
,這兩種構(gòu)建動(dòng)畫都是將組件和動(dòng)畫一起完成的。有些時(shí)候,我們只是想動(dòng)效復(fù)用,而不關(guān)心組件構(gòu)建,這個(gè)時(shí)候就可以使用 AnimatedBuilder
了。
AnimatedBuilder 介紹
根據(jù)官方文檔說(shuō)明,AnimatedBuilder
的使用要點(diǎn)如下:
- An
AnimatedBuilder
understands how to render the transition. —— AnimatedBuilder 知道如何渲染轉(zhuǎn)場(chǎng)動(dòng)效。 - An
AnimatedBuilder
doesn’t know how to render the widget, nor does it manage theAnimation
object. ——AnimatedBuilder
不知道(或者準(zhǔn)確說(shuō)不應(yīng))如何渲染組件,也不管理組件對(duì)象。 - Use
AnimatedBuilder
to describe an animation as part of a build method for another widget. If you simply want to define a widget with a reusable animation, use anAnimatedWidget
. —— 使用AnimatedBuilder
作為其他組件的動(dòng)效描述。如果只是想復(fù)用一個(gè)帶有動(dòng)效的組件,那么應(yīng)該使用AnimatedWidget
。這個(gè)可以看我們之前關(guān)于 AnimatedWidget 的介紹:Flutter 入門與實(shí)戰(zhàn)(九十四):讓你的組件擁有三維動(dòng)效 - Examples of AnimatedBuilders in the Flutter API:
BottomSheet
,ExpansionTile
,PopupMenu
,ProgressIndicator
,RefreshIndicator
,Scaffold
,SnackBar
,TabBar
,TextField
. —— 在 Flutter 中,有很多組件使用 AnimatedBuilder 構(gòu)建動(dòng)效。
這段話的核心要點(diǎn)就是 AnimatedBuilder
應(yīng)該只負(fù)責(zé)動(dòng)畫效果的管理,而不應(yīng)該管理組件構(gòu)建。如果混在一起使用,就失去設(shè)計(jì)者的初衷了。這就好比我們的狀態(tài)管理和界面一樣,一個(gè)負(fù)責(zé)業(yè)務(wù)邏輯,一個(gè)負(fù)責(zé)界面渲染,從而實(shí)現(xiàn)解耦和復(fù)用。這個(gè)AnimatedBuilder
就是專門復(fù)制動(dòng)效管理的,并且應(yīng)當(dāng)努力實(shí)現(xiàn)復(fù)用。AnimatedBuilder
的定義如下:
const?AnimatedBuilder({ ????Key??key, ????required?Listenable?animation, ????required?this.builder, ????this.child, ??})?:?assert(animation?!=?null), ???????assert(builder?!=?null), ???????super(key:?key,?listenable:?animation);
其中關(guān)鍵的參數(shù)是builder
,builder
用于構(gòu)建組件的轉(zhuǎn)變動(dòng)作,在 builder
里可以對(duì)要渲染的子組件進(jìn)行轉(zhuǎn)變操作,然后返回變換后的組件。builder
的定義如下,其中 child
實(shí)際就是 AnimatedBuilder
的 child
參數(shù),可以根據(jù)需要是否使用。
Widget?Function(BuildContext?context,?Widget??child)
Transform 組件介紹
在 Flutter 中,提供了一個(gè)專門用于對(duì)子組件進(jìn)行轉(zhuǎn)換操作的,定義如下:
const?Transform({ ????Key??key, ????required?this.transform, ????this.origin, ????this.alignment, ????this.transformHitTests?=?true, ????Widget??child, ??})?:?assert(transform?!=?null), ???????super(key:?key,?child:?child);
這里的參數(shù)說(shuō)明如下:
transform
是一個(gè)Matrix4
對(duì)象,用于定義三維空間的變換操作。origin
是一個(gè)坐標(biāo)偏移量,實(shí)際會(huì)加入到Matrix4
的translation
(平移)中。alignment
:即轉(zhuǎn)變進(jìn)行的參考方位。child
:被轉(zhuǎn)換的子組件。
我們可以通過(guò) Transform
,實(shí)現(xiàn) AnimatedBuilder
的動(dòng)效管理,也就是在 AnimatedBuilder
中,通過(guò)構(gòu)建 Transform
對(duì)象實(shí)現(xiàn)動(dòng)效。
應(yīng)用
基本概念講清楚了(敲黑板:很多時(shí)候大家都是直接簡(jiǎn)單看一下文檔就開始用,甚至干脆復(fù)制示例代碼就上,結(jié)果很可能會(huì)用得不對(duì)),可以開始擼代碼了。我們來(lái)實(shí)現(xiàn)下面的動(dòng)效。
這里其實(shí)是兩個(gè)組件,通過(guò) AnimatedBuilder
做了動(dòng)效轉(zhuǎn)換。在動(dòng)效的一半時(shí)間是文字“點(diǎn)擊按鈕變出小姐姐”,之后的一半將組件更換為了小姐姐的圖片了。使用AnimatedBuilder
的實(shí)現(xiàn)代碼如下:
class?RotationSwitchAnimatedBuilder?extends?StatelessWidget?{ ??final?Widget?child1,?child2; ??final?Animation<double>?animation; ??const?RotationSwitchAnimatedBuilder( ??????{Key??key, ??????required?this.animation, ??????required?this.child1, ??????required?this.child2}) ??????:?super(key:?key); ??@override ??Widget?build(BuildContext?context)?{ ????return?AnimatedBuilder( ??????animation:?animation, ??????builder:?(context,?child)?{ ????????if?(animation.value?<?0.5)?{ ??????????return?Transform( ????????????transform:?Matrix4.identity() ??????????????..rotateZ(animation.value?*?pi) ??????????????..setEntry(0,?1,?-0.003), ????????????alignment:?Alignment.center, ????????????child:?child1, ??????????); ????????}?else?{ ??????????return?Transform( ????????????transform:?Matrix4.identity() ??????????????..rotateZ(pi) ??????????????..rotateZ(animation.value?*?pi) ??????????????..setEntry(1,?0,?0.003), ????????????child:?child2, ????????????alignment:?Alignment.center, ??????????); ????????} ??????}, ????); ??} }
注意第2個(gè)組件多轉(zhuǎn)了180度,是未來(lái)保證停止后正好旋轉(zhuǎn)360度,以免圖片倒過(guò)來(lái)。另外就是這里的 child1
和 child2
也可以修改為使用 WidgetBuilder
函數(shù)來(lái)在需要的時(shí)候再構(gòu)建組件。使用這個(gè)RotationSwitchAnimatedBuilder
的組件就十分簡(jiǎn)單了,將需要操作的兩個(gè)組件作為參數(shù)傳過(guò)來(lái),然后控制 Animation
對(duì)象來(lái)刷新界面就好了,對(duì)應(yīng)的代碼如下:
class?AnimatedBuilderDemo?extends?StatefulWidget?{ ??const?AnimatedBuilderDemo({Key??key})?:?super(key:?key); ??@override ??_AnimatedBuilderDemoState?createState()?=>?_AnimatedBuilderDemoState(); } class?_AnimatedBuilderDemoState?extends?State<AnimatedBuilderDemo> ????with?SingleTickerProviderStateMixin?{ ??late?Animation<double>?animation; ??late?AnimationController?controller; ??@override ??void?initState()?{ ????super.initState(); ????controller?= ????????AnimationController(duration:?const?Duration(seconds:?1),?vsync:?this); ????animation?=?Tween<double>(begin:?0,?end:?1.0).animate(controller); ??} ??@override ??Widget?build(BuildContext?context)?{ ????return?Scaffold( ??????appBar:?AppBar( ????????title:?Text('AnimatedBuilder?動(dòng)畫'), ??????), ??????body:?RotationSwitchAnimatedBuilder( ????????animation:?animation, ????????child1:?Center( ??????????child:?Container( ????????????padding:?EdgeInsets.all(10), ????????????margin:?EdgeInsets.all(10), ????????????constraints:?BoxConstraints(minWidth:?double.infinity), ????????????decoration:?BoxDecoration( ??????????????borderRadius:?BorderRadius.circular(4.0), ??????????????gradient:?LinearGradient( ????????????????colors:?[ ??????????????????Colors.orange, ??????????????????Colors.green, ????????????????], ??????????????), ????????????), ????????????child:?Text( ??????????????'點(diǎn)擊按鈕變出小姐姐', ??????????????style:?TextStyle( ????????????????fontSize:?20, ????????????????color:?Colors.white, ????????????????fontWeight:?FontWeight.bold, ??????????????), ??????????????textAlign:?TextAlign.center, ????????????), ??????????), ????????), ????????child2:?Center( ??????????child:?Image.asset('images/beauty.jpeg'), ????????), ??????), ??????floatingActionButton:?FloatingActionButton( ????????child:?Icon(Icons.play_arrow,?color:?Colors.white), ????????onPressed:?()?{ ??????????if?(controller.status?==?AnimationStatus.completed)?{ ????????????controller.reverse(); ??????????}?else?{ ????????????controller.forward(); ??????????} ????????}, ??????), ????); ??} ??@override ??void?dispose()?{ ????controller.dispose(); ????super.dispose(); ??} }
復(fù)用的話也很容易了,比如我們將一個(gè)圓形和一個(gè)矩形組件傳過(guò)去,一樣可以復(fù)用這個(gè)動(dòng)畫效果。
總結(jié)
本篇介紹了 AnimatedBuilder
的概念和應(yīng)用, Flutter 提供 AnimatedBuilder
組件的核心理念是為了創(chuàng)建和管理可復(fù)用的動(dòng)畫效果。在使用的時(shí)候,應(yīng)該將動(dòng)畫效果和組件構(gòu)建分離,從而使得AnimatedBuilder
構(gòu)建的動(dòng)畫效果可以在需要的時(shí)候得到復(fù)用。
以上就是Flutter使用AnimatedBuilder實(shí)現(xiàn)動(dòng)效復(fù)用的詳細(xì)內(nèi)容,更多關(guān)于Flutter動(dòng)效復(fù)用的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android手機(jī)注冊(cè)登錄時(shí)獲取驗(yàn)證碼之后倒計(jì)時(shí)功能(知識(shí)點(diǎn)總結(jié))
這篇文章主要介紹了Android手機(jī)注冊(cè)登錄時(shí)獲取驗(yàn)證碼之后倒計(jì)時(shí)(知識(shí)點(diǎn)總結(jié))功能,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有參考借鑒價(jià)值,需要的的朋友參考下吧2017-01-01Android實(shí)現(xiàn)引導(dǎo)頁(yè)的圓點(diǎn)指示器
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)引導(dǎo)頁(yè)的圓點(diǎn)指示器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06Android編程使用加速度傳感器實(shí)現(xiàn)搖一搖功能及優(yōu)化的方法詳解
這篇文章主要介紹了Android編程使用加速度傳感器實(shí)現(xiàn)搖一搖功能及優(yōu)化的方法,結(jié)合實(shí)例形式分析了Android傳感器的調(diào)用方法、參數(shù)含義及具體使用技巧,需要的朋友可以參考下2017-08-08Android實(shí)現(xiàn)給TableLayou繪制邊框的方法
這篇文章主要介紹了Android實(shí)現(xiàn)給TableLayou繪制邊框的方法,涉及Android TableLayou布局控制相關(guān)技巧,需要的朋友可以參考下2016-03-03Android啟動(dòng)頁(yè)出現(xiàn)白屏、黑屏的解決方案
這篇文章主要給大家介紹了關(guān)于Android啟動(dòng)頁(yè)出現(xiàn)白屏、黑屏的解決方案,這一個(gè)需求是每位Android開發(fā)者都需要的,最近發(fā)現(xiàn)了一個(gè)不錯(cuò)的解決方法,所以分享給大家,文中給出了詳細(xì)的介紹,需要的朋友可以參考下。2017-12-12Android SDK Manager無(wú)法更新問(wèn)題解決辦法
這篇文章主要介紹了Android SDK Manager無(wú)法更新問(wèn)題解決辦法的相關(guān)資料,需要的朋友可以參考下2017-04-04