在前面搭好環境後以及快速了解的dart的文法後,開始學習Flutter的基礎Widget!!
目錄
Flutter Widget庫介紹
Widget
StatelessWidget
StatefulWidget
State
State生命周期
Text
使用字型
在asset中聲明
使用字型
Package中的字型
按鈕
自定義按鈕外觀
圖檔
ImageProvider
從asset中加載圖檔
從網絡加載圖檔
TextField
在Flutter中大部分類皆繼承Widget,Widget的功能是“描述一個UI元素的配置資料”,它就是說,Widget其實并不是表示最終繪制在裝置螢幕上的顯示元素,而隻是顯示元素的一個配置資料。實際上,Flutter中真正代表螢幕上顯示元素的類是
Element
,也就是說Widget隻是描述
Element
的一個配置。
Flutter Widget庫介紹
Flutter提供了一套豐富、強大的基礎widget,在基礎widget庫之上Flutter又提供了一套Material風格(Android預設的視覺風格)和一套Cupertino風格(iOS視覺風格)的widget庫。要使用基礎widget庫,需要先導入:
// Android
import 'package:flutter/widgets.dart';
// iOS
import 'package:flutter/cupertino.dart';
Widget
下面是Widget類的源代碼:
abstract class Widget extends DiagnosticableTree {
/// Initializes [key] for subclasses.
const Widget({ this.key });
final Key key;
@protected
Element createElement();
@override
String toStringShort() {
return key == null ? '$runtimeType' : '$runtimeType-$key';
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.defaultDiagnosticsTreeStyle = DiagnosticsTreeStyle.dense;
}
static bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType
&& oldWidget.key == newWidget.key;
}
}
- 類Key:目前Widget的唯一标示符,決定Widget是否複用。在canUpdate方法中判斷。
- 方法createElement:建立顯示的對象。
StatelessWidget
StatelessWidget用于不需要維護狀态的場景,它通常在
build
方法中通過嵌套其它Widget來建構UI,在建構過程中會遞歸的建構其嵌套的Widget
StatefulWidget
abstract class StatefulWidget extends Widget {
const StatefulWidget({ Key key }) : super(key: key);
@override
StatefulElement createElement() => new StatefulElement(this);
@protected
State createState();
}
-
間接繼承自StatefulElement
類,與StatefulWidget相對應(作為其配置資料)。Element
中可能會多次調用StatefulElement
來建立狀态(State)對象。createState()
-
用于建立和Stateful widget相關的狀态,它在Stateful widget的生命周期中可能會被多次調用。例如,當一個Stateful widget同時插入到widget樹的多個位置時,Flutter framework就會調用該方法為每一個位置生成一個獨立的State執行個體,其實,本質上就是一個createState()
對應一個State執行個體。StatefulElement
State
一個StatefulWidget類會對應一個State類,State表示與其對應的StatefulWidget要維護的狀态,State中的儲存的狀态資訊可以:
- 在widget build時可以被同步讀取。
- 在widget生命周期中可以被改變,當State被改變時,可以手動調用其
方法通知Flutter framework狀态發生改變,Flutter framework在收到消息後,會重新調用其setState()
方法重新建構widget樹,進而達到更新UI的目的build
State生命周期
// 初始化狀态,隻執行一次
void initState() { }
// 當widget依賴的對象發生變化時調用,例如全局的主題或語言
void didChangeDependencies() { }
// 當widget重新建構時調用,根據canUpdate方法判斷
void didUpdateWidget(covariant T oldWidget) { }
// 建構UI
void build() { }
// 調試模式下,熱重載執行,Release模式不會執行
void reassemble() { }
// 當widget被移除時調用
void deactivate() { }
// 當widget被永久移除時,可以做釋放資源
void dispose() { }
widget被加載顯示的時候會依次調用initState,didChangeDependencies,build等方法。
點選熱重載時會依次調用reassemble,didUpdateWidget,build等方法。
發生界面切換時會依次調用deactivate,dispose等方法。
Text
顯示文本,其一些樣式屬性和Android的TextView類似,比如,文本對齊方式,大小,顔色等等。
使用字型
在Flutter中使用字型分兩步完成。首先在
pubspec.yaml
中聲明它們,以確定它們會打包到應用程式中。然後通過
TextStyle
屬性使用字型。
在asset中聲明
要将字型打檔案打包到應用中,和使用其它資源一樣,要先在
pubspec.yaml
中聲明它。然後将字型檔案複制到在
pubspec.yaml
中指定的位置。如
flutter:
fonts:
- family: Raleway
fonts:
- asset: assets/fonts/Raleway-Regular.ttf
- asset: assets/fonts/Raleway-Medium.ttf
weight: 500
- asset: assets/fonts/Raleway-SemiBold.ttf
weight: 600
- family: AbrilFatface
fonts:
- asset: assets/fonts/abrilfatface/AbrilFatface-Regular.ttf
使用字型
// 聲明文本樣式
const textStyle = const TextStyle(
fontFamily: 'Raleway',
);
// 使用文本樣式
var buttonText = const Text(
"Use the font for this text",
style: textStyle,
);
Package中的字型
要使用Package中定義的字型,必須提供
package
參數。例如,假設上面的字型聲明位于
my_package
包中。然後建立TextStyle的過程如下
const textStyle = const TextStyle(
fontFamily: 'Raleway',
package: 'my_package', //指定包名
);
如果在package包内部使用它自己定義的字型,也應該在建立文本樣式時指定
package
參數,如上例所示。
一個包也可以隻提供字型檔案而不需要在pubspec.yaml中聲明。 這些檔案應該存放在包的
lib/
檔案夾中。字型檔案不會自動綁定到應用程式中,應用程式可以在聲明字型時有選擇地使用這些字型。假設一個名為my_package的包中有一個字型檔案:
lib/fonts/Raleway-Medium.ttf
然後,應用程式可以聲明一個字型,如下面的示例所示:
flutter:
fonts:
- family: Raleway
fonts:
- asset: assets/fonts/Raleway-Regular.ttf
- asset: packages/my_package/fonts/Raleway-Medium.ttf
weight: 500
lib/
是隐含的,是以它不應該包含在asset路徑中。
在這種情況下,由于應用程式本地定義了字型,是以在建立TextStyle時可以不指定
package
參數:
const textStyle = const TextStyle(
fontFamily: 'Raleway',
);
按鈕
Material widget庫中提供了多種按鈕Widget如RaisedButton、FlatButton、OutlineButton等,它們都是直接或間接對RawMaterialButton的包裝定制,是以他們大多數屬性都和
RawMaterialButton
一樣。在介紹各個按鈕時我們先介紹其預設外觀,而按鈕的外觀大都可以通過屬性來自定義,我們在後面統一介紹這些屬性。另外,所有Material 庫中的按鈕都有如下相同點:
- 按下時都會有“水波動畫”。
- 有一個
屬性來設定點選回調,當按鈕按下時會執行該回調,如果不提供該回調則按鈕會處于禁用狀态,禁用狀态不響應使用者點選。onPressed
有這幾種:RaisedButton,FlatButton,OutlineButton,IconButton 具體使用可檢視Flutter Gallery Demo。
自定義按鈕外觀
const FlatButton({
...
@required this.onPressed, //按鈕點選回調
this.textColor, //按鈕文字顔色
this.disabledTextColor, //按鈕禁用時的文字顔色
this.color, //按鈕背景顔色
this.disabledColor,//按鈕禁用時的背景顔色
this.highlightColor, //按鈕按下時的背景顔色
this.splashColor, //點選時,水波動畫中水波的顔色
this.colorBrightness,//按鈕主題,預設是淺色主題
this.padding, //按鈕的填充
this.shape, //外形
@required this.child, //按鈕的内容
})
圖檔
Flutter中,我們可以通過Image來加載并顯示圖檔,Image的資料源可以是asset、檔案、記憶體以及網絡。
ImageProvider
ImageProvider
是一個抽象類,主要定義了圖檔資料擷取的接口
load()
,從不同的資料源擷取圖檔需要實作不同的
ImageProvider
,如
AssetImage
是實作了從Asset中加載圖檔的ImageProvider,而
NetworkImage
實作了從網絡加載圖檔的ImageProvider。
從asset中加載圖檔
- 在工程根目錄下建立一個
,并将圖檔avatar.png拷貝到該目錄。images目錄
- 在
中的pubspec.yml
部分添加如下内容:flutter
assets: - images/avatar.png
- 加載圖檔
Image(
image: AssetImage("images/avatar.png"),
width: 100.0
);
Image也提供了一個快捷的構造函數
Image.asset
用于從asset中加載、顯示圖檔:
Image.asset("images/avatar.png",
width: 100.0,
)
從網絡加載圖檔
Image(
image: NetworkImage(
"https://avatars2.githubusercontent.com/u/20411648?s=460&v=4"),
width: 100.0,
)
Image也提供了一個快捷的構造函數
Image.network
用于從網絡加載、顯示圖檔:
Image.network(
"https://avatars2.githubusercontent.com/u/20411648?s=460&v=4",
width: 100.0,
)
TextField
TextField用于文本輸入,它提供了很多屬性。
const TextField({
...
TextEditingController controller,
FocusNode focusNode,
InputDecoration decoration = const InputDecoration(),
TextInputType keyboardType,
TextInputAction textInputAction,
TextStyle style,
TextAlign textAlign = TextAlign.start,
bool autofocus = false,
bool obscureText = false,
int maxLines = 1,
int maxLength,
bool maxLengthEnforced = true,
ValueChanged<String> onChanged,
VoidCallback onEditingComplete,
ValueChanged<String> onSubmitted,
List<TextInputFormatter> inputFormatters,
bool enabled,
this.cursorWidth = 2.0,
this.cursorRadius,
this.cursorColor,
...
})
- controller:編輯框的控制器,通過它可以設定/擷取編輯框的内容、選擇編輯内容、監聽編輯文本改變事件。大多數情況下我們都需要顯式提供一個controller來與文本框互動。如果沒有提供controller,則TextField内部會自動建立一個。
- focusNode:用于控制TextField是否占有目前鍵盤的輸入焦點。它是我們和鍵盤互動的一個handle。
- InputDecoration:用于控制TextField的外觀顯示,如提示文本、背景顔色、邊框等。
-
keyboardType:用于設定該輸入框預設的鍵盤輸入類型,取值如下:
| TextInputType枚舉值 | 含義 | | ------------------- | --------------------------------------------------- | | text | 文本輸入鍵盤 | | multiline | 多行文本,需和maxLines配合使用(設為null或大于1) | | number | 數字;會彈出數字鍵盤 | | phone | 優化後的電話号碼輸入鍵盤;會彈出數字鍵盤并顯示"* #" | | datetime | 優化後的日期輸入鍵盤;Android上會顯示“: -” | | emailAddress | 優化後的電子郵件位址;會顯示“@ .” | | url | 優化後的url輸入鍵盤; 會顯示“/ .” |
- textInputAction:鍵盤動作按鈕圖示(即Enter鍵位圖示),它是一個枚舉值,有多個可選值,全部的取值清單讀者可以檢視API文檔
- style:正在編輯的文本樣式。
- textAlign: 輸入框内編輯文本在水準方向的對齊方式。
- autofocus: 是否自動擷取焦點。
- obscureText:是否隐藏正在編輯的文本,如用于輸入密碼的場景等,文本内容會用“•”替換。
- maxLines:輸入框的最大行數,預設為1;如果為
,則無行數限制。null
- maxLength和maxLengthEnforced :maxLength代表輸入框文本的最大長度,設定後輸入框右下角會顯示輸入的文本計數。maxLengthEnforced決定當輸入文本長度超過maxLength時是否阻止輸入,為true時會阻止輸入,為false時不會阻止輸入但輸入框會變紅。
- onChange:輸入框内容改變時的回調函數;注:内容改變事件也可以通過controller來監聽。
- onEditingComplete和onSubmitted:這兩個回調都是在輸入框輸入完成時觸發,比如按了鍵盤的完成鍵(對号圖示)或搜尋鍵(?圖示)。不同的是兩個回調簽名不同,onSubmitted回調是
類型,它接收目前輸入内容做為參數,而onEditingComplete不接收參數。ValueChanged<String>
- inputFormatters:用于指定輸入格式;當使用者輸入内容改變時,會根據指定的格式來校驗。
- enable:如果為
,則輸入框會被禁用,禁用狀态不接收輸入和事件,同時顯示禁用态樣式(在其decoration中定義)。false
- cursorWidth、cursorRadius和cursorColor:這三個屬性是用于自定義輸入框光标寬度、圓角和顔色的。
參考Flutter中文網