在 Flutter 中,有兩類經常使用的 Widget:github
無狀態的 StatelessWidgetbash
有狀態的 StatefulWidgetapp
在開發過程當中,咱們常常須要繼承它們兩來實現本身的 Widget。less
一個 StatelessWidget 是不能被改變的,好比:Icon
、Text
等。ide
若是你的控件一旦顯示,就不須要再作任何的變動,那麼你應該使用 StatelessWidget。函數
實現一個本身的 StatelessWidget 很簡單。post
當你看到下面這個例子🌰時,你就知道它有多簡單了。ui
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return _buildMyWidget(context);
}
複製代碼
看,只要在 build()
中返回你的視圖就能夠了。spa
一個 StatefulWidget 是有狀態的,可變的。
它能夠改變本身的外觀,以響應用戶的操做或者數據的變化。
好比:CheckBox
、Switch
..
咱們之因此可以改變一個 StatefulWidget,是由於它有一個設置狀態的函數:
setState((){
// 更新狀態、數據
})
複製代碼
調用這個函數後,就會觸發 StatefulWidget 的視圖樹重建。
所以,當咱們須要一個可交互的,即能根據用戶操做或數據變化而改變視圖的 Widget 時,那就得用上 StatelessWidget 了。
如今,來建立一個自定義的 StatefulWidget:
實現一個 StatefulWidget,它是 Widget 的外層。
class FavoriteStatefulWidget extends StatefulWidget {
// 必須重寫 createState(),返回一個 State,它包含了視圖和交互邏輯
@override
State<StatefulWidget> createState() => _FavoriteStatefulWidgetState();
}
複製代碼
實現一個 State,它提供了真正的 Widget 視圖和交互邏輯。
class _FavoriteStatefulWidgetState extends State<FavoriteStatefulWidget> {
bool _isFavorited = true;
int _favoriteCount = 41;
void _toggleFavorite() {
// 經過 setState() 更新數據
// 組件樹就會自動刷新了
setState(() {
if (_isFavorited) {
_favoriteCount -= 1;
_isFavorited = false;
} else {
_favoriteCount += 1;
_isFavorited = true;
}
});
}
// 重寫 build() 函數,構建視圖樹
@override
Widget build(BuildContext context) => Row(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: EdgeInsets.all(0),
child: IconButton(
icon: (_isFavorited ? Icon(Icons.star) : Icon(Icons.star_border)),
color: Colors.red[500],
onPressed: _toggleFavorite,
),
),
SizedBox(
width: 18,
child: Container(
child: Text('$_favoriteCount'),
),
),
],
);
}
複製代碼
使用這個自定義的 StatefulWidget 看看效果。
main() => runApp(MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(
title: Text('Flutter Demo'),
),
body: Container(
color: Colors.white,
child: Center(
child: FavoriteStatefulWidget(),
),
),
),
));
複製代碼
從上面的例子中能夠看到,StatefulWidget 會要求提供一個含有視圖樹的 State。
既然 State 可以控制一個視圖的狀態,那它確定會有一系列的生命週期。
上圖就是 State 的生命週期圖。
StatefulWidget.createState()
Framework 調用會經過調用 StatefulWidget.createState()
來建立一個 State。
initState()
新建立的 State 會和一個 BuildContext 產生關聯,此時認爲 State 已經被安裝好了,initState()
函數將會被調用。
一般,咱們能夠重寫這個函數,進行初始化操做。
didChangeDependencies()
在 initState()
調用結束後,這個函數會被調用。
事實上,當 State 對象的依賴關係發生變化時,這個函數總會被 Framework 調用。
build()
通過以上步驟,系統認爲一個 State 已經準備好了,就會調用 build()
來構建視圖。
咱們須要在這個函數中,返回一個 Widget。
deactivate()
當 State 被暫時從視圖樹中移除時,會調用這個函數。
頁面切換時,也會調用它,由於此時 State 在視圖樹中的位置發生了變化,須要先暫時移除後添加。
⚠️注意,重寫的時候必需要調用 super.deactivate()
。
dispose()
當 State 被永久的從視圖樹中移除,Framework 會調用該函數。
在銷燬前觸發,咱們能夠在這裏進行最終的資源釋放。
在調用這個函數以前,總會先調用 deactivate()
。
⚠️注意,重寫的時候必需要調用 super.dispose()
。
didUpdateWidget(covariant T oldWidget)
當 widget 的配置發生變化時,會調用這個函數。
好比,Hot-reload 的時候就會調用這個函數。
這個函數調用後,會調用 build()
。
setState()
當我須要更新 State 的視圖時,須要手動調用這個函數,它會觸發 build()
。