相對于iOS開發(fā),F(xiàn)lutter的布局更具有靈活性,每個頁面設(shè)計都不一樣,相同頁面可選擇的布局方式也不一樣,如果單純的說應(yīng)該如何去布局,我覺得不現(xiàn)實,大家可以參考下 Flutter官方的布局教程 。接下來,筆者,通過項目中的一個頁面,來一步一步的拆解布局的流程。整個過程,基本上按照拆解、組件封裝、具體布局這三步來的。
創(chuàng)新互聯(lián)公司成立于2013年,先為烏審等服務(wù)建站,烏審等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為烏審企業(yè)網(wǎng)站制作PC+手機+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。
根據(jù)設(shè)計圖,可以看出整體可以分成兩部分,上面一部分是系統(tǒng)介紹模塊,下面一部分是真正的登錄內(nèi)容,因為涉及到疊加,因此考慮用Stack;
系統(tǒng)介紹模塊部分:整體也是涉及到疊加,考慮用Stack,分為四部分。最底部漸變色背景用一個contanier,無須指定位置,全視圖擴展;載放logo圖標(biāo)在上一層,用Image。最后兩個Text同級放在最上層。Image,Text各用Positioned包裹去指定位置。
登錄內(nèi)容模塊是最外層是一個Contanier容器,去控制背景色和圓角。然后是一個Column元素,逐行排列。
第一行為Image,
第二行為Text,
第三行可以看成一個小Column,分兩塊進(jìn)行布局
第四行可以看成一個小Column,分兩塊進(jìn)行布局
第五行可以看作一個TextButton,
第六行可以看作一個Row,分三塊進(jìn)行布局
通過上面這樣一步一步的分析后,基本上對大致的布局有了一個了解,最外層的控件大致選對(只要能實現(xiàn)的話,就是復(fù)雜度以及效率的問題),然后一步一步的拆解每一行的元素,如果有重復(fù)的或者覺得可以封裝出來的部分,則進(jìn)行下一步。
每一行的拆解,大致也是按照這個思路來進(jìn)行,因此筆者在這里就不做講解了。
在做到第三第四行的時候,發(fā)現(xiàn)這兩個很相似,而且設(shè)計到一些交互邏輯,筆者就想對第三第四行的這種展示進(jìn)行封裝,覺得今后的布局可能會用到,因此在這一步,可以先把這一塊兒抽離出一個控件。利用TextField來實現(xiàn)這種輸入操作,具體的實現(xiàn)筆者不再詳細(xì)的描述了。
經(jīng)過這一步,整體的規(guī)劃設(shè)計圖已經(jīng)有了,各個組件也都有了,接下來的工作就是組裝了。
具體布局設(shè)計到一些細(xì)節(jié)的地方,例如整體Column的居中對齊(crossAxisAlignment)、間隔(Padding或Container包裹,筆者更喜歡用SizedBox占位)、居左居右居中(Align)、點擊事件(GestureDetector)以及圓角(BorderRadius)等一些特殊情況。
像第六行row是放在底部的,就可以在第六行前面增加一個Spacer()去填充空白區(qū)域。
對文字顏色大小等,可以用TextStyle直接設(shè)置。
對于輸入框的刪除按鈕,可以用Offstage這種Flutter特有的控制顯示隱藏的控件。
這種方法最常見,但是有些地方引用的話,刷新的成本比較大,刷新的是整個頁面,數(shù)據(jù)太多加載太慢的話,會有閃爍的現(xiàn)象
這種方法類似于iOS中的set方法,通過設(shè)置某個屬性的時候,去刷新某個控件。在flutter中這種刷新方式,是對上面setState(){}方法的改進(jìn),根本的方法還是setState(){},只不過是通過方法去刷新某個控件。如下:
首先在pubspec.yaml中添加provider依賴
下面通過provider來實現(xiàn)一個發(fā)送驗證碼的案例。
創(chuàng)建一個TimerModel文件
頁面布局如下:
現(xiàn)象:
flutter頁面通過present跳轉(zhuǎn)原生頁面后,原生頁面上的點擊會首先響應(yīng)下面的flutter頁面中的內(nèi)容(比如按鈕什么的)。
這是flutter框架一直存在的一個bug。在github上有相關(guān)的issue。
原因推測:
推測是flutter對控制器(或者view)加了分類,重寫了控制器的點擊事件,用來計算是否在對應(yīng)的點擊位置有flutter響應(yīng)事件。沒有的話再扔出去點擊事件。
解決方案1:
在原生控制器中,加入點擊事件的幾個方法的空實現(xiàn),用以覆蓋flutter框架中的實現(xiàn):
-(void)touchesBegan:(NSSetUITouch * *)touches withEvent:(UIEvent *)event{
}
-(void)touchesMoved:(NSSetUITouch * *)touches withEvent:(UIEvent *)event{
}
-(void)touchesCancelled:(NSSetUITouch * *)touches withEvent:(UIEvent *)event{
}
-(void)touchesEnded:(NSSetUITouch * *)touches withEvent:(UIEvent *)event{
}
讓事件不被flutter截獲即可。
解決方案2:
直接切換window的根控制器到原生控制器即可。別忘暫時保存flutter控制器。
在返回時再切換回flutter中。
解決方案3:
在flutter跳轉(zhuǎn)到原生頁面之前,在flutter中加上一個蒙層,用來隔絕手勢往flutter下面的view傳遞。原生頁面返回flutter時再移除這個蒙層。
Element管理Widget和RenderObject。
widget保持顯示當(dāng)前的頁面狀態(tài),當(dāng)widget產(chǎn)生點擊等交互,調(diào)用setState()改變element中管理的state,
返回用navigator的pop方法
使用navigator的pushNamed方法push到對應(yīng)的頁面
在導(dǎo)航的目的頁面的build方法里用ModalRoute.of(context)方法獲取需要的參數(shù):
第二個頁面返回到第一個頁面的時候如果要帶參數(shù),可以使用async異步方法來實現(xiàn)
用navigator的push方法,在頁面的初始化方法中傳遞參數(shù):
轉(zhuǎn)自
在 Flutter 中,有兩類常用的 Widget:
在開發(fā)過程中,我們經(jīng)常需要繼承它們兩來實現(xiàn)自己的 Widget。
一個 StatelessWidget 是不能被改變的,比如: Icon 、 Text 等。
如果你的控件一旦顯示,就不需要再做任何的變更,那么你應(yīng)該使用 StatelessWidget 。
實現(xiàn)一個自己的 StatelessWidget 很簡單。
當(dāng)你看到下面這個例子?時,你就知道它有多簡單了。
看,只要在 build() 中返回你的視圖就可以了。
一個 StatefulWidget 是有狀態(tài)的,可變的。
它可以改變自己的外觀,以響應(yīng)用戶的操作或者數(shù)據(jù)的變化。
比如: CheckBox 、 Switch ..
我們之所以能夠改變一個 StatefulWidget ,是因為它有一個設(shè)置狀態(tài)的函數(shù):
調(diào)用這個函數(shù)后,就會觸發(fā) StatefulWidget 的視圖樹重建。
因此,當(dāng)我們需要一個可交互的,即能根據(jù)用戶操作或數(shù)據(jù)變化而改變視圖的 Widget 時,那就得用上 StatelessWidget 了。
現(xiàn)在,來創(chuàng)建一個自定義的 StatefulWidget:
從上面的例子中可以看到, StatefulWidget 會要求提供一個含有視圖樹的 State 。
既然 State 能夠控制一個視圖的狀態(tài),那它肯定會有一系列的生命周期。
上圖就是 State 的生命周期圖。