1. 簡介
在Flutter中,Widget是個非常基本的東西,我在上一章就說過,Flutter中只要是界面都是Widget,你可以把它就理解成是控件,但是又和Android的View控件不同的是,在Flutter中,包括Padding
、Align
、手勢檢測的GestureDetector
等等,都算是Widget
。
其實大多數時候,你就可以把Widget直接理解成UI控件就行了,因爲Padding
、Align
、GestureDetector
等等也都是爲UI服務的,你就可以理解成Flutter中只要與UI有關的屬性都可以算是控件。
2. Widget的狀態
在Android中,我們可以直接通過更新數據來達到刷新UI的目的。但是如果使用Flutter,就像我們前面說的計數器的Demo,如果直接通過StatelessWidget
也就是無狀態Widget的話,是沒法進行刷新UI的,只能寫一個死界面,也就是說如果在Flutter中界面寫出來的就是一個死界面,只有通過刷新狀態才能更新UI。
Widget有兩個直接子類:StatelessWidget
和StatefulWidget
:
StatelessWidget
:這個是無狀態Widget,實現build()
方法後,就不可再變化,哪怕他的狀態改變了。這句話可能有點矛盾,但是我來舉個例子,比方說現在有一個StatelessWidget
,他的內容就是一個Text
,而這個Text
的內容則顯示了counter
這個變量。當這個頁面出現的時候,取了當時counter
的值並顯示了出來,但是我們後續不管counter
這個值怎麼改變,界面都是不會顯示出來的。StatefulWidget
:這個是有狀態Widget,當你有狀態需要改變的時候就可以通過他來改變狀態。
State的幾種狀態:
名稱 | 狀態 |
---|---|
initState | create之後被insert到渲染樹時調用的,只會調用一次 |
didChangeDependencies | state依賴的對象發生變化時調用 |
didUpdateWidget | Widget狀態改變時候調用,可能會調用多次 |
build | 構建Widget時調用 |
deactivate | 當移除渲染樹的時調用 |
dispose | Widget即將銷燬時調用 |
3. StatelessWidget
這個類相對簡單,只需要實現build()
方法就可以了。
StatelessWidget
用於不需要維護狀態的場景,也就是說如果他需要顯示的某一個參數的值發生變化了他也不變。
class Test extends StatelessWidget {
Test({Key key, this.title}) : super(key: key);
final String title;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
title: Text("$title"),
),
body: Text("1234"),
);
}
}
上面代碼就演示了一個StatelessWidget
的例子,功能是根據傳入的title
在界面的title
了上顯示出來。只實現了build()
方法和構造方法。其中構造方法參數Key
是必須得有的,而且如果該Widget還有其他狀態的話,也需要寫入構造方法。接着調用build()
方法,將傳入的title
在界面的title
上顯示出來。
例如,如果我們調用它:
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Test(title: 'Flutter Demo Home Page'),
);
}
結果是:
4. StatefulWidget
與StatelessWidget
相對的就是StatefulWidget
。它的重點在於可以根據狀態來更新。
他較於StatelessWidget
,少了我們常用的build()
方法,多了createState()
方法。下面我就來講一下他的用法,我還是拿上面的Test
做例子。
class Test extends StatefulWidget {
Test({Key key, this.title}) : super(key: key);
final String title;
@override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
String _title;
@override
void initState() {
setState(() {
_title = widget.title;
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
title: Text("$_title"),
),
body: Text("1234"),
);
}
}
先看Test
類,他繼承自StatefulWidget
,由於這個頁面需要根據傳入的參數來顯示title
,所以有一個狀態title
,並在構造方法中寫入了他。接着調用了createState()
方法。這個方法是所有StatefulWidget
必須的,主要是爲這個Widget創建他對應的State。
於是我們就在下面創建一個新的類,類名叫_TestState
,繼承自State<Test>
。由於Widget有title
這個狀態,並且需要在界面中顯示出來,所以爲了降低他們的耦合度,我們在State類中也創建一個叫_title
的狀態,並_title = widget.title;
。
接下來是一個initState()
方法,這個方法也是State必須的,在上面Widget的狀態中我們講到過,這個是初始化State的,同時在initSate()
裏面,我們寫了一個setState()
,也就是說我們告訴Flutter說這個方法裏面的參數改變了接着Widget的狀態也得改變。最後就是build()
方法。
接下來我們調用它:
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Test(title: '1234'),
);
}
結果是: