在naive開發中,大家對view肯定很熟悉,它代表著所有控制元件的祖先。在flutter中,也存在這麼一個所有控制元件的祖先---Widget。Widget類是一個抽象類,定義在系統的framework.dart中,我們可以看下它的實現類非常多,好幾百個都不止。其實,Flutter中的Widget概念更廣泛,它不僅可以表示UI元素,也可以表示一些功能性的元件如:用於手勢檢測的 GestureDetector、用於應用主題資料傳遞的Theme等等。
Widght子類介紹
學習一個新UI技術,我們肯定首先會學習文字控制元件,所以我們首先開啟flutter中的最簡單的文字控制元件---Text來看下。Text控制元件首先繼承自StatelessWidget,然後StatelessWidget又繼承自Widget,也就是說Text是間接繼承自Widget,其他的比如圖片控制元件什麼的也是一樣,這裡就不一一貼圖了。
那麼是否所有控制元件都是繼承自StatelessWidget呢?答案是否定的,比如Checkbox是繼承自StatefulWidget,然後StatefulWidget繼承自Widget。
既然有些控制元件是繼承自StatelessWidget,又有些控制元件是繼承自StatefulWidget,那麼這二者的區別是什麼呢?StatelessWidget是用於不需要維護狀態的場景,在構建過程中會遞迴的構建其巢狀的Widget。StatefulWidget是動態的,新增了一個新的介面'createState()'用於建立和Stateful widget相關的狀態'State',它在Stateful widget的生命週期中可能會被多次呼叫。
簡單專案構造
接下來我們來看看最簡單的flutter介面類是什麼樣的。基本的介面也可以使用StatelessWidget方式構造和StatefulWidget方式構造,區別也是需不需要維護狀態。
StatelessWidget方式
系統預設的方式就是繼承自StatelessWidget的方式,複寫其中的build方法進行控制元件的填充。這裡將具體頁面內容封裝到了MyHomePage類中,也是為了防止build方法層級太亂。
StatefulWidget方式
StatefulWidget方式和StatelessWidget區別在於,StatefulWidget擁有修改狀態的createState方法。本例中,我們首先在state中定義了一個字串,然後再build中將該字串設定到了介面上,然後在state中開了延時一秒,然後執行更新字串的操作,最後介面上一秒後字串就自動更新成新字串了,這種方式是不是比java中找到控制元件,然後去賦值的方式要簡單不少呢?這裡需要注意的是,不能在State的構造方法裡直接呼叫狀態資料的修改,這樣是不會起作用的,因為此時系統還沒執行到build方法,所以介面還沒顯示出來,何來的修改?
State生命週期
上面說到state修改時會涉及到介面的生命週期問題,那麼state完整的生命週期是什麼樣的呢?想知道這個答案,我們就必須對State裡面的回撥方法進行打點。那麼有哪些方法呢,開啟State類的構造檢視來看下,將其中的方法進行復寫,然後檢視呼叫順序即可。
打好的輸出點結果如下圖:
從結果可以看到,首先執行initState方法,然後是didChangeDependencies,然後是build,然後是setState,然後又執行了一次build。這裡其實執行到build以後介面就已經顯示出來了,後面執行setState後由於我們有一次修改字串內容的操作,所以導致頁面發生了重繪,結果是再次執行了build方法。於是我們可以畫出生命週期流程圖大致如下:
State生命週期方法簡單介紹:
initState:當Widget第一次插入到Widget樹時會被呼叫,對於每一個State物件,Flutter framework只會呼叫一次該回撥。
didChangeDependencies:初始化時,在initState()之後立刻呼叫,另外,當依賴的InheritedWidget rebuild,會觸發此介面被呼叫。
build:繪製介面,當setState觸發的時候會再次被呼叫。
didUpdateWidget:狀態改變的時候會呼叫該方法,比如呼叫了setState。
deactivate:當State物件從樹中被移除時,會呼叫此回撥。
dispose:當State物件從樹中被永久移除時呼叫;通常在此回撥中釋放資源。
基本控制元件介紹
1、Text
'Text'是展示單一格式的文字Widget(類似於Android的'TextView')。前面舉例子也用過Text,它相當於是一個純文字的展示。
設定字型大小、顏色等基本功能當然是支援的,flutter中Text的構造方法中提供了一組可選命名引數,裡面就包括了這些基本設定屬性。
修改字型等這些基本屬性只需要用到上面那麼多可選引數中的style即可,於是我們可以用dart中可選命名引數A:b的方式進行賦值,如下:
2.RichText
如果需要顯示更為豐富樣式的文字(比如一段文字中文字不同顏色),可以使用'RichText'或者'Text.rich',如下例中我們定義了一段不同顏色的文字內容。
3.DefaultTextStyle
在widget樹中,文字的樣式預設是可以被繼承的,因此,如果在widget樹的某一個節點處設定一個預設的文字樣式,那麼該節點的子樹中所有文字都會預設使用這個樣式。相當於Android中定義的Theme。
4.FlutterLogo
這個Widget用於顯示Flutter的logo。。。
5.Icon
主要用於顯示內建圖示
6.Image
顯示圖片的`Widget`。圖片常用的格式主要有bmp,jpg,png,gif,webp等,Android中並不是天生支援gif和webp動圖,但是這一特性在flutter中被很好的支援了
7.Iamge.asset
在工程目錄下建立目錄,如:assets,將圖片放入此目錄,接下來開啟根目錄的pubspec.yaml配置檔案進行配置,而後就可以使用了。
8.Image.file
在sd卡中放入一張圖片。然後利用**path_provider**庫獲取sd卡根目錄(Dart庫版本可以在:https://pub.dartlang.org/packages查詢)。
9.Image.network
從網路上直接顯示圖片,所以給出網路地址即可。
> Flutter 1.0,載入https時候經常出現證照錯誤。必須斷開AS開啟app
10.Image.memory
從byte陣列中獲取資料並顯示
這裡介紹一下圖片的大小處理,類似於android中的imageview的scaleType屬性。
BoxFit.fill:填充,忽略原有的寬高比,填滿為止
BoxFit.contain:包含,不改變原有比例讓容器包含整個圖片,容器多餘部分填充背景
BoxFit.cover :覆蓋,不改變原有比例,讓圖片充滿整個容器,圖片多餘部分裁剪
BoxFit.fitWidth:橫向圖片填充
BoxFit.fitHeight:縱向圖片填充
BoxFit.none:原始大小居中
BoxFit.scaleDown:圖片大小小於容器事相當於none,圖片大小大於容器時縮小圖片大小實現contain
11.CircleAvatar
主要用來顯示使用者的頭像,任何圖片都會被剪下為圓形。
12.FadeInImage
當使用預設'Image'顯示圖片時,您可能會注意到它們在載入完成後會直接顯示到螢幕上。這可能會讓使用者產生視覺突兀。如果最初顯示一個佔位符,然後在影象載入完顯示時淡入,我們可以使用'FadeInImage'來達到這個目的!
image = FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
image: 'https://flutter.io/images/homepage/header-illustration.png',
);
13.按鈕
Material widget庫中提供了多種按鈕Widget如RaisedButton、FlatButton、OutlineButton等,它們都是直接或間接對RawMaterialButton的包裝定製,所以他們大多數屬性都和`RawMaterialButton`一樣。所有Material 庫中的按鈕都有如下相同點:
1. 按下時都會有“水波動畫”。
2. 有一個`onPressed`屬性來設定點選回撥,當按鈕按下時會執行該回撥,如果不提供該回撥則按鈕會處於禁用狀態,禁用狀態不響應使用者點選。
14.RaisedButton
"漂浮"按鈕,它預設帶有陰影和灰色背景
RaisedButton(
child: Text("normal"),
onPressed: () => {},
)
15.FlatButton
扁平按鈕,預設背景透明並不帶陰影
FlatButton(
child: Text("normal"),
onPressed: () => {},
)
16.OutlineButton
預設有一個邊框,不帶陰影且背景透明。
OutlineButton(
child: Text("normal"),
onPressed: () => {},
)
17.IconButton
可點選的Icon
IconButton(
icon: Icon(Icons.thumb_up),
onPressed: () => {},
)
18.輸入框
獲取控制元件焦點
FocusNode: 與Widget繫結,代表了這個Widget的焦點
FocusScope: 焦點控制範圍
FocusScopeNode:控制焦點
獲取控制元件的輸入內容
獲取輸入內容有兩種方式:
1. 定義兩個變數,用於儲存使用者名稱和密碼,然後在onChange觸發時,各自儲存一下輸入內容。
2. 通過controller直接獲取。
TextFormField
`TextFormField`比普通輸入框`TextField`多了一些屬性,其中 ***validator***用於設定驗證回撥。在單獨使用時與`TextField`沒有太大的區別。當結合`From`,利用`From`可以對輸入框進行分組,然後進行一些統一操作(驗證)
總結:打好基礎,才能建起高樓大廈。本次主要是分享了一下flutter入門的一些基礎知識,包括系統簡單控制元件相關知識、state生命週期相關知識,這些知識點都將是學好flutter必須掌握的一塊敲門磚。有關控制元件種類實在太多,只能等專案中實戰再慢慢去使用了,希望有了這個文章以後到時候能降低這些控制元件的使用難度,提升自己的開發速度。