前言
上一篇文章我們了解了在Flutter中三種常見的布局方式Row,Column,Stack,并對他們做了具體的舉例和簡單的應(yīng)用。我們會在下一步的項目開發(fā)中做更具體的介紹和應(yīng)用。今天給大家?guī)淼氖荈lutter中兩個核心的基類:StatelessWidget(無狀態(tài)部件)和StatefulWidget(有狀態(tài)部件),我們?nèi)粘5拈_發(fā)中,自定義的小部件都是需要基于這兩個類。接下來我們就對這兩種類型的Widget做一些深入的探索。
StatelessWidget
StatelessWidget-無狀態(tài)小部件,這里的無狀態(tài)體現(xiàn)在哪里吶?什么是個無狀態(tài)?其實無狀態(tài)的意思就是說當它被渲染到屏幕的那一刻,就無法改變了,就算內(nèi)部做動態(tài)的數(shù)據(jù)修改,我的頁面依然還是第一次呈現(xiàn)的樣子。換句話說,就是我本身不具備重繪能力,我一開始是什么樣子,我就一直是什么樣字。接下來我們通過代碼驗證一下:
//這個代碼就是新建的空工程內(nèi)的那個點擊?,計數(shù)++的那個例子
//我們基于StatelessWidget創(chuàng)建一個MyHomePage部件
class MyHomePage extends StatelessWidget {
// final int count = 0; //final = let, statelessWidget 下變量的默認修飾符
int count = 0; //為了驗證在無狀態(tài)可以改變值,這里我們用可變的類型
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('StatelessWidget'),
),
body: Center(
child: Chip(label: Text('$count')), //這是個有圓角效果的label $xx flutter數(shù)據(jù)format
),
floatingActionButton: FloatingActionButton( //漂浮在右下角的button
child: Icon(Icons.add), //button 上的+icon
onPressed: (){ //點擊事件 是一個callback 函數(shù)
count += 1;
print('count = $count'); //這里我們打印一下
},
),
);
}
}
控制臺輸出:
Performing hot reload...
Syncing files to device iPhone 11 Pro Max...
Reloaded 1 of 504 libraries in 940ms.
flutter: count = 1
flutter: count = 2
flutter: count = 3
flutter: count = 4
flutter: count = 5
flutter: count = 6
此時界面顯示結(jié)果:

到此,我們會發(fā)現(xiàn)在StatelessWidget中是可以修改值的,只是修改完之后,并沒有動態(tài)的渲染到屏幕上。這也就說明StatelessWidget是一個一次性渲染的Widget,一旦渲染到屏幕就不會再做任何改變。在項目中對于那些只做靜態(tài)顯示,沒有數(shù)據(jù)變化的界面,我們就可以基于StatelessWidget來定義。
StatefulWidget
StatefulWidget-有狀態(tài)小部件,那這里的有狀態(tài)又是怎么個體現(xiàn)吶?我們知道在iOS開發(fā)中,通過重寫UIView的drawRect:方法后,當數(shù)據(jù)發(fā)生改變時,會通過調(diào)用setNeedsDisplay方法,內(nèi)部會通過調(diào)用其代理方法displayLayer或drawLayer:inContext:方法,將當前layer的contents中的內(nèi)容刪除,以便騰出新的空間,最后觸發(fā)drawInRect:方法進行重繪,將新的內(nèi)容再交給contents,從而達到界面刷新效果。
每一個StatefulWiget,都有一個State 與它一一對應(yīng),并遵守了當前Widget協(xié)議,并實現(xiàn)了build() 方法,在Widget中返回當前State。(iOS角度的理解,可能不太準確,等進一步理解后再修改這里的描述吧)
class MyHomePage extends StatefulWidget {
// 這里還可以定義一些property
// 構(gòu)造方法
// 對外暴露一些方法和屬性
// createState() 建立綁定關(guān)系
@override
State<StatefulWidget> createState() { //獲取當前State(或者說是建立Widget和State的綁定)
return _ZZState();
}
}
class _ZZState extends State<MyHomePage>{ //遵守MyHomePage協(xié)議/接口
int count = 0;
@override
Widget build(BuildContext context) { //重寫build協(xié)議方法
return Scaffold(
appBar: AppBar(
title: Text('StateMangerDemo'),
),
body: Center(
child: Chip(label: Text('$count')),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: (){
count += 1; //當值發(fā)生改變時
setState(() {});// 類似于setNeedsDisplay->drawRect:
// 這里是 setState() -> build() 會抹掉當前Widget內(nèi)容并重新繪制
print('count = $count');
},
),
);
}
}
當點擊按鈕時,控制臺輸出:
Performing hot restart...
Syncing files to device iPhone 11 Pro Max...
Restarted application in 2,449ms.
flutter: count = 1
flutter: count = 2
flutter: count = 3
flutter: count = 4
界面顯示:

就是這么簡單,就是這么神奇! 關(guān)于
setState() -> build()的原理,在后面的文章中會深入探索。
總結(jié)
本篇文章帶大家了解了一下StatelessWidget和StatefulWidget基本概念和區(qū)別,并通過代碼做了進一步的驗證和演示。