注:本文從我的公衆號(島前嶼端)中遷移從新發布前端
Flutter 是谷歌的移動 UI 框架,能夠從單個代碼庫快速的爲移動端(iOS & Android)、Web、桌面端、嵌入式設備上構建高質量的原生用戶界面和應用程序。web
上一篇中咱們主要說一下簡單的 Hello World 是如何實現的。那麼此次我就來講說,關於組件的兩個形式。編程
可是在此以前,我以爲仍是有必要簡單的來講一說關於 Dart 語言的一些東西。後端
Dart 語言是由谷歌公司開發的網絡編程語言,於2011年10月10日發佈。Dart是一個小型的編譯型語言。瀏覽器
Dart 主要支持和麪向 3 個不一樣平臺的開發需求:服務器
Dart 吸取了一些後端語言和前端語言的一部分特色。在 Dart 中全部的東西都是對象,function 是對象;String 是對象;Number是對象;null 也是對象。(是否是有內味兒了?)markdown
public
" "private
",以 "_
" 開頭則表示僅對當前域有效,既是私有的。Ok,關於 Dart 語言就簡單介紹這點好了。更多的 Dart 語言內容請參考:dart.dev/網絡
在簡單介紹關於 Dart 語言後,就能夠說說 StatelessWidget 和 StatefulWidget 了。上一篇中說到 StatelessWidget 和 StatefulWidget 均繼承自 Widget,都是 Widget 的抽象類。【傳送門】框架
(StatelessWidget 的繼承關係)less
(StatefulWidget 的繼承關係)
從源碼中咱們能夠看出且證明了 StatelessWidget 和 StatefulWidget 均繼承自 Widget 且都是 Widget 的抽象類 abstract。
這裏我將他們的關係整理了一下。
(StatelessWidget 和 StatefulWidget 的繼承關係圖)
如圖所示,而這也從側面證明了 Dart 中全部對象都是 Object。
在以前的文章中我也有提到過 StatelessWidget 和 StatefulWidget 雖然都是 Widget 的抽象類。可是他們之間仍是有區別的,它們分別用於實現不一樣場景下使用的 Widget 組件。
StatelessWidget 是無狀態的,意味着沒法經過數據變動而更新。
這樣,咱們來實現一個小🌰,你就知道了。
項目依然是咱們的 MyApp,咱們要先 實現一個 名叫 UnchangeWidget 的類,讓它 繼承於 StatelessWidget。
再來實現一個按鈕,經過按鈕的點擊事件來更新咱們的文字內容。
// 繼承 StatelessWidget 意味着沒法經過數據變動而改變內容
class UnchangeWidget extends StatelessWidget {
String setText = '我是原來的文字'; // 聲明變量文字 - 默認值
@override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
Text(setText), // 使用變量 setText 來設置 Text 的內容
RaisedButton(
child: Text('改變內容'),
onPressed: () { // 按鈕點擊事件 - 改變內容
print('觸發了按鈕');
setText = '我是新的文字'; // 賦值新文字內容
},
)
],
));
}
}
複製代碼
結果以下:
(文字內容並無更新)
即便觸發了按鈕,且對 setText 進行了賦值,可是咱們的 Text 內容依然沒有更新。
StatefulWidget 是有狀態的,意味着能夠經過數據變動而更新,須要經過 setState 來管理狀態。
Ok,那麼咱們再來改寫一下這個 UnchangeWidget ,將它改寫爲 繼承於 StatefulWidget。
這裏能夠經過編輯器的快速修復功能來進行代碼的改寫。
// 繼承 StatefulWidget 意味着能夠經過數據變動而改變內容
class UnchangeWidget extends StatefulWidget {
String setText = '原來的內容'; // 變量設置文字 - 默認值
@override // 建立狀態控制類的簡寫方式,這裏的 new 也能夠省略
_UnchangeWidgetState createState() => _UnchangeWidgetState();
}
class _UnchangeWidgetState extends State<UnchangeWidget> {
@override
Widget build(BuildContext context) {
return Container(
child: Column(children: <Widget>[
Text(widget.setText), // 使用變量 setText 來設置 Text 的內容
RaisedButton(
child: Text('改變內容'),
onPressed: () { // 按鈕點擊事件 - 改變內容
print('觸發了按鈕');
setState(() { // 調用狀態變動函數
widget.setText = '我是新的文字'; // 賦值新文字內容
print('狀態變動文字更新');
});
},
),
]),
);
}
}
複製代碼
結果以下:
(使用 setState 更新內容)
這裏咱們能夠從結果中看到,經過按鈕的觸發調用 setState 來進行狀態的更新從而更新了 Text 的文字內容。
這時候一些少俠們就不樂意了:「StatefulWidget 用了 setState 來更新內容,StatelessWidget 沒有,不公平! 」
哈哈哈哈,不要緊,那麼咱們就來試一試!我就喜歡你這種勇於發出不一樣聲音的人。
咱們如今繼續使用 StatefulWidget 的代碼,而後直接將繼承對象更新爲 StatelessWidget。
(更改繼承類型爲 StatelessWidget)
那麼咱們來看看結果會是怎麼樣?在命令行中鍵入 R 後耐心等待……
來來來,讓咱們掌聲送給這幾位勇敢的少俠,喜提滿屏紅。
爲何會這樣呢?由於它們在源碼中的實現是不一樣的。
(StatelessWidget 源碼部分)
(StatefulWidget 源碼部分)
在源碼中 StatelessWidget 和 StatefulWidget 的實現方式不同。
我能夠簡單翻譯一下。
StatelessWidget 部分:
此方法的實現必須僅依賴於:
- widget 的字段,它們自己不能隨着時間進行改變,以及任何從 [context] 環境中使用的狀態。
若是 widget 的 [build] 方法依賴於其餘的東西,那麼就請改成使用 [StatefulWidget]。
StatefulWidget 部分:
子類應該重寫此方法以返回其關聯的新建立的[State]子類實例。
(1)在構建 widget 時,能夠同步獲取狀態信息。
(2)在 widget 的生命週期內,widget 的實現須要確保在狀態發生改變時使用 [State.setState] 來及時通知 [State] 須要更改的信息。
因此由此可知 StatelessWidget 是不參與組件生命 State 狀態管理的,亦沒有對 State 的關聯操做,而 StatefulWidget 則是參與實現了 State 的重寫,亦要求使用者重寫 createState 以保證對 State 的關聯。
就是說若是你想實現一個動態的可更新數據的組件就使用 StatefulWidget,若是隻是想展現靜態的文字信息或內容就使用 StatelessWidget。