Android Flutter實(shí)現(xiàn)3D動(dòng)畫效果示例詳解
前言
上一篇我們介紹了 Animation
和 AnimationController
的使用,這是最基本的動(dòng)畫構(gòu)建類。但是,如果我們想構(gòu)建一個(gè)可復(fù)用的動(dòng)畫組件,通過外部參數(shù)來控制其動(dòng)畫效果的時(shí)候,上一篇的方法就不太合適了。在 Flutter 中提供了 AnimatedWidget
組件用于構(gòu)建可復(fù)用的動(dòng)畫組件。本篇我們用 AnimatedWidget
來實(shí)現(xiàn)組件的3D 旋轉(zhuǎn)效果,如下圖所示。
AnimatedWidget 簡介
AnimatedWidget
是一個(gè)抽象的 StatefulWidget
, 構(gòu)造方法如下所示。
const?AnimatedWidget({ ????Key??key, ????required?this.listenable, ??})?:?assert(listenable?!=?null), ???????super(key:?key);
主要在于接收一個(gè) listenable
參數(shù),通常會(huì)是 Animation
對象。在 AnimatedWidget
內(nèi)部的_AnimatedState
類中,會(huì)添加該對象變化監(jiān)聽回調(diào),進(jìn)而刷新界面。
class?_AnimatedState?extends?State<AnimatedWidget>?{ ??@override ??void?initState()?{ ????super.initState(); ????widget.listenable.addListener(_handleChange); ??} ??@override ??void?didUpdateWidget(AnimatedWidget?oldWidget)?{ ????super.didUpdateWidget(oldWidget); ????if?(widget.listenable?!=?oldWidget.listenable)?{ ??????oldWidget.listenable.removeListener(_handleChange); ??????widget.listenable.addListener(_handleChange); ????} ??} ??@override ??void?dispose()?{ ????widget.listenable.removeListener(_handleChange); ????super.dispose(); ??} ??void?_handleChange()?{ ????setState(()?{ ??????//?The?listenable's?state?is?our?build?state,?and?it?changed?already. ????}); ??} ?? ??//?... }
可以看到,只需要將 Animation
對象傳給 AnimatedWidget
對象后,就不需要我們之前那樣自己寫 addListener
之類的處理了。而整個(gè)動(dòng)畫可以交給外部其他對象來控制,從而實(shí)現(xiàn)動(dòng)畫組件的復(fù)用。
3D 旋轉(zhuǎn)動(dòng)畫的實(shí)現(xiàn)
3D 旋轉(zhuǎn)的實(shí)現(xiàn)比較簡單,在 Container
組件有兩個(gè)參數(shù)控制轉(zhuǎn)換(transform),分別是:
transform
:Matrix4
對象,可以實(shí)現(xiàn)圍繞 X、Y、Z軸的旋轉(zhuǎn)、平移,以及變形等效果。關(guān)于Matrix4
涉及到很多矩陣運(yùn)算和線性代數(shù)的知識,可以參考 Matrix4的源碼自行溫習(xí)一下大學(xué)的數(shù)學(xué)知識。transformAlignment
:轉(zhuǎn)換的對齊方式,可以理解為起點(diǎn)位置,可以使用Alignment
對象來設(shè)置。
有了這個(gè)基礎(chǔ),我們就可以定義3D 旋轉(zhuǎn)動(dòng)效了,我們定義一個(gè)通用的組件,ThreeDAnimatedWidget
:
class?ThreeDAnimatedWidget?extends?AnimatedWidget?{ ??final?Widget?child; ??const?ThreeDAnimatedWidget( ??????{Key??key,?required?Animation<double>?animation,?required?this.child}) ??????:?super(key:?key,?listenable:?animation); ??@override ??Widget?build(BuildContext?context)?{ ????final?animation?=?listenable?as?Animation<double>; ????return?Center( ??????child:?Container( ????????transform:?Matrix4.identity() ??????????..rotateY(2?*?pi?*?animation.value) ??????????..setEntry(1,?0,?0.01), ????????transformAlignment:?Alignment.center, ????????child:?child, ??????), ????); ??} }
這里我們設(shè)置的是圍繞中心點(diǎn)繞 Y 軸旋轉(zhuǎn),并使用 setEntry
設(shè)置了一定的傾斜角 (這會(huì)更有立體感)。實(shí)際我們也可以設(shè)置圍繞 X 軸或 Z 軸旋轉(zhuǎn)。接下來就是這個(gè)動(dòng)畫組件的應(yīng)用了,我們構(gòu)建一個(gè)帶有陰影的文字(看起來像立體字)作為這個(gè)動(dòng)畫的子組件,其他的控制和上一篇的是類似的,完整代碼如下:
class?AnimatedWidgetDemo?extends?StatefulWidget?{ ??const?AnimatedWidgetDemo({Key??key})?:?super(key:?key); ??@override ??_AnimatedWidgetDemoState?createState()?=>?_AnimatedWidgetDemoState(); } class?_AnimatedWidgetDemoState?extends?State<AnimatedWidgetDemo> ????with?SingleTickerProviderStateMixin?{ ??late?Animation<double>?animation; ??late?AnimationController?controller; ??@override ??void?initState()?{ ????super.initState(); ????controller?= ????????AnimationController(duration:?const?Duration(seconds:?3),?vsync:?this); ????animation?=?Tween<double>(begin:?0.0,?end:?1.0).animate(controller); ??} ??@override ??Widget?build(BuildContext?context)?{ ????return?Scaffold( ??????appBar:?AppBar( ????????title:?Text('AnimatedWidget?動(dòng)畫'), ??????), ??????body:?ThreeDAnimatedWidget( ????????animation:?animation, ????????child:?Text( ??????????'島上碼農(nóng)', ??????????style:?TextStyle( ????????????fontSize:?42.0, ????????????color:?Colors.blue, ????????????fontWeight:?FontWeight.bold, ????????????shadows:?[ ??????????????Shadow( ??????????????????blurRadius:?2, ??????????????????offset:?Offset(2.0,?1.0), ??????????????????color:?Colors.blue[900]!), ????????????], ??????????), ????????), ??????), ??????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(); ??} }
可以看到,這個(gè) ThreeDAnimatedWidget
可以做到復(fù)用了,在需要這樣動(dòng)效的場景里,按照上面的方式給它傳入 Animation
對象和子組件就可以了。例如我們將文字修改為一張圖片。
//... body:?ThreeDAnimatedWidget( ??animation:?animation, ??child:?Image.asset( ????'images/avatar.jpg', ????width:?100, ????height:?100, ??), ), //...
圖片旋轉(zhuǎn).gif
總結(jié)
本篇介紹了 AnimatedWidget
的使用,通過 AnimatedWidget
可以構(gòu)建可復(fù)用的動(dòng)畫組件。同時(shí),還通過 Container
的 transform
屬性加上 AnimatedWidget
實(shí)現(xiàn)了三維空間的旋轉(zhuǎn)效果。實(shí)際開發(fā)過程中,我們可以基于 AnimatedWidget
構(gòu)建很多個(gè)性化的、可復(fù)用的動(dòng)畫組件,提升應(yīng)用的趣味性。
以上就是Android Flutter實(shí)現(xiàn)3D動(dòng)畫效果示例詳解的詳細(xì)內(nèi)容,更多關(guān)于Flutter 3D動(dòng)畫的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
解析:ClickOnce通過URL傳遞參數(shù) XXX.application?a=1
本篇文章是對ClickOnce通過URL傳遞參數(shù)進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-06-06Android中使用七牛云存儲(chǔ)進(jìn)行圖片上傳下載的實(shí)例代碼
這篇文章主要介紹了Android中使用七牛云存儲(chǔ)進(jìn)行圖片上傳下載的實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2016-08-08Android scrollTo和scrollBy方法使用解析
在一個(gè)View中,系統(tǒng)提供了scrollTo、scrollBy兩種方式來改變一個(gè)View的位置,下面通過本文給大家介紹Android scrollTo和scrollBy方法使用解析,需要的朋友參考下吧2018-01-01Android開發(fā)No Focused Window ANR產(chǎn)生原理解析
這篇文章主要為大家介紹了Android開發(fā)No Focused Window ANR產(chǎn)生原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-07-07android視頻截屏&手機(jī)錄屏實(shí)現(xiàn)代碼
本篇文章主要介紹了android視頻截屏&手機(jī)錄屏實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-07-07android實(shí)現(xiàn)拍照或從相冊選取圖片
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)拍照或從相冊選取圖片,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-03-03Android實(shí)現(xiàn)自定義滑動(dòng)刻度尺方法示例
這篇文章主要給大家介紹了關(guān)于Android實(shí)現(xiàn)自定義滑動(dòng)刻度尺的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對各位Android開發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04Android編程出現(xiàn)Button點(diǎn)擊事件無效的解決方法示例
這篇文章主要介紹了Android編程出現(xiàn)Button點(diǎn)擊事件無效的解決方法,結(jié)合實(shí)例形式分析了Android編程中出現(xiàn)Button點(diǎn)擊事件無效的原因及相關(guān)的解決方法,需要的朋友可以參考下2018-02-02