flutter中使用流式布局示例詳解
簡(jiǎn)介
我們?cè)陂_發(fā)web應(yīng)用的時(shí)候,有時(shí)候?yàn)榱诉m應(yīng)瀏覽器大小的調(diào)整,需要?jiǎng)討B(tài)對(duì)頁面的組件進(jìn)行位置的調(diào)整。這時(shí)候就會(huì)用到flow layout,也就是流式布局。
同樣的,在flutter中也有流式布局,這個(gè)流式布局的名字叫做Flow。事實(shí)上,在flutter中,F(xiàn)low通常是和FlowDelegate一起使用的,F(xiàn)lowDelegate用來設(shè)置Flow子組件的大小和位置,通過使用FlowDelegate.paintChildre可以更加高效的進(jìn)行子widget的重繪操作。今天我們來詳細(xì)講解flutter中flow的使用。
Flow和FlowDelegate
先來看下Flow的定義:
class Flow extends MultiChildRenderObjectWidget
Flow繼承自MultiChildRenderObjectWidget,說它里面可以包含多個(gè)子widget。
再來看下它的構(gòu)造函數(shù):
Flow({ Key? key, required this.delegate, List<Widget> children = const <Widget>[], this.clipBehavior = Clip.hardEdge, }) : assert(delegate != null), assert(clipBehavior != null), super(key: key, children: RepaintBoundary.wrapAll(children));
可以看到Flow中主要有三個(gè)屬性,分別是delegate,children和clipBehavior。
children很好理解了,它就是Flow中的子元素。
clipBehavior是一個(gè)Clip類型的變量,表示的是如何對(duì)widget進(jìn)行裁剪。這里的默認(rèn)值是none。
最后一個(gè)非常重要的屬性就是FlowDelegate,FlowDelegate主要用來控制Flow中子widget的位置變換。所以,當(dāng)我們?cè)贔low中定義好子widget之后,剩下的就是定義FlowDelegate來控制如何展示這些子widget。
FlowDelegate是一個(gè)抽象類,所以我們?cè)谑褂玫臅r(shí)候,需要繼承它。
FlowDelegate有幾個(gè)非常重要的方法:
Size getSize(BoxConstraints constraints) => constraints.biggest;
這個(gè)方法用來定義Flow的size,對(duì)于Flow來說,它的size是和子widget的size是獨(dú)立的,F(xiàn)low的大小通過getSize方法來定義。
接下來是getConstraintsForChild方法:
BoxConstraints getConstraintsForChild(int i, BoxConstraints constraints) => constraints;
getConstraintsForChild用來控制子widget的Constraints。
paintChildren用來控制如何繪制子widget,也是我們必須要實(shí)現(xiàn)的方法:
void paintChildren(FlowPaintingContext context);
FlowDelegate還有兩個(gè)方法,分別用來判斷是否需要Relayout和Repaint,這兩個(gè)方法的參數(shù)都是FlowDelegate:
bool shouldRelayout(covariant FlowDelegate oldDelegate) => false; bool shouldRepaint(covariant FlowDelegate oldDelegate);
Flow的應(yīng)用
有了上面的介紹,我們基本上已經(jīng)了解如何構(gòu)建Flow了,接下來我們通過一個(gè)具體的例子來加深對(duì)Flow的理解。
在本例中,我們主要是使用Flow來排列幾個(gè)圖標(biāo)。
首先我們定義一個(gè)圖標(biāo)的數(shù)組:
final List<IconData> buttonItems = <IconData>[ Icons.home, Icons.ac_unit, Icons.adb, Icons.airplanemode_active, Icons.account_box_rounded, ];
然后通過每個(gè)圖標(biāo)對(duì)應(yīng)的IconData來構(gòu)建一個(gè)IconButton的widget:
Widget flowButtonItem(IconData icon) { return Padding( padding: const EdgeInsets.symmetric(vertical: 10.0), child: IconButton( icon: Icon(icon, size: 50, color: Colors.blue ), onPressed: () { buttonAnimation.status == AnimationStatus.completed ? buttonAnimation.reverse() : buttonAnimation.forward(); }, ) ); }
這里我們使用的是IconButton,為了在不同IconButton之間留一些空間,我們將IconButton封裝在Padding中。
在onPressed方法中,我們希望能夠處理一些動(dòng)畫效果。這里的buttonAnimation是一個(gè)AnimationController對(duì)象:
AnimationController buttonAnimation = AnimationController( duration: const Duration(milliseconds: 250), vsync: this, );
有了flowButtonItem之后,我們就可以構(gòu)建Flow了:
Widget build(BuildContext context) { return Flow( delegate: FlowButtonDelegate(buttonAnimation: buttonAnimation), children: buttonItems.map<Widget>((IconData icon) => flowButtonItem(icon)).toList(), ); }
Flow的child就是我們剛剛創(chuàng)建的flowButtonItem,F(xiàn)lowButtonDelegate是我們需要新建的類,因?yàn)橹霸跇?gòu)建flowButtonItem的時(shí)候,我們希望進(jìn)行一些動(dòng)畫的繪制,而FlowDelegate又是真正用來控制子Widget繪制的類,所以我們需要將buttonAnimation作為參數(shù)傳遞給FlowButtonDelegate。
下面是FlowButtonDelegate的定義:
class FlowButtonDelegate extends FlowDelegate { FlowButtonDelegate({required this.buttonAnimation}) : super(repaint: buttonAnimation); final Animation<double> buttonAnimation; @override bool shouldRepaint(FlowButtonDelegate oldDelegate) { return buttonAnimation != oldDelegate.buttonAnimation; } @override void paintChildren(FlowPaintingContext context) { double dy = 0.0; for (int i = 0; i < context.childCount; ++i) { dy = context.getChildSize(i)!.height * i; context.paintChild( i, transform: Matrix4.translationValues( 0, dy * buttonAnimation.value, 0, ), ); } }
FlowButtonDelegate繼承自FlowDelegate,并且傳入了buttonAnimation對(duì)象。
這里我們根據(jù)buttonAnimation是否發(fā)生變化來決定是否進(jìn)行Repaint。
如果需要進(jìn)行Repaint,那么就要調(diào)用paintChildren的方法。
在paintChildren中,我們根據(jù)child自身的height和buttonAnimation的值來進(jìn)行動(dòng)畫的繪制。
那么buttonAnimation的值是如何變化的呢?這就要回顧之前我們創(chuàng)建flowButtonItems的onPress方法了。
在onPress方法中,我們調(diào)用了buttonAnimation.reverse或者buttonAnimation.forward這兩個(gè)方法來修改buttonAnimation的值。
運(yùn)行之后的效果如下:
初始狀態(tài)下,所有的組件都是在一起的。
當(dāng)我們點(diǎn)擊上面的圖標(biāo)的時(shí)候,我們可以得到下面的界面:
圖標(biāo)在動(dòng)畫中展開了。
總結(jié)
Flow是一種比較復(fù)雜的layout組件,如果和動(dòng)畫進(jìn)行結(jié)合使用,可以得到非常完美的效果。
本文的例子:github.com/ddean2009/l…
以上就是flutter中使用流式布局示例詳解的詳細(xì)內(nèi)容,更多關(guān)于flutter 流式布局的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android學(xué)習(xí)之AppWidget筆記分享
這篇文章主要為大家詳細(xì)介紹了Android學(xué)習(xí)筆記之AppWidget的相關(guān)資料,感興趣的小伙伴們可以參考一下2016-08-08EditText監(jiān)聽方法,實(shí)時(shí)的判斷輸入多少字符
在EditText提供了一個(gè)方法addTextChangedListener實(shí)現(xiàn)對(duì)輸入文本的監(jiān)控。本文分享了EditText監(jiān)聽方法案例,需要的朋友一起來看下吧2016-12-12Android實(shí)現(xiàn)檢測(cè)實(shí)體按鍵事件并屏蔽
這篇文章主要介紹了Android實(shí)現(xiàn)檢測(cè)實(shí)體按鍵事件并屏蔽 ,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08Android小知識(shí)之OkHttp的2種請(qǐng)求方式詳解
OkHttp可以說是如今最為流行的網(wǎng)絡(luò)請(qǐng)求框架之一,下面這篇文章主要給大家介紹了關(guān)于Android小知識(shí)之OkHttp的2種請(qǐng)求方式的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2018-10-10android實(shí)現(xiàn)撲克卡片翻轉(zhuǎn)
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)撲克卡片翻轉(zhuǎn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05深入解析Android系統(tǒng)中應(yīng)用程序前后臺(tái)切換的實(shí)現(xiàn)要點(diǎn)
這篇文章主要介紹了Android系統(tǒng)中應(yīng)用程序前后臺(tái)切換的實(shí)現(xiàn)要點(diǎn),除了切換操作的效果之外還重點(diǎn)講解了判斷程序運(yùn)行于前臺(tái)還是后臺(tái)的方法,需要的朋友可以參考下2016-04-04詳解Android App中使用VideoView來實(shí)現(xiàn)視頻播放的方法
這篇文章主要介紹了Android App中使用VideoView來實(shí)現(xiàn)視頻播放的方法,舉例講解了VideoView組件中setVidePath(String path)和setVideoURI(Uri uri)的用法,需要的朋友可以參考下2016-04-04解決android studio 打開java文件 內(nèi)容全變了的問題
這篇文章主要介紹了解決android studio 打開java文件 內(nèi)容全變了的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-03-03Android自定義View實(shí)現(xiàn)心形圖案
這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)心形圖案,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09