【Flutter 基礎】State x Widget

注:本文從我的公衆號(島前嶼端)中遷移從新發布前端

Flutter 是谷歌的移動 UI 框架,能夠從單個代碼庫快速的爲移動端(iOS & Android)、Web、桌面端、嵌入式設備上構建高質量的原生用戶界面和應用程序。web


上一篇中咱們主要說一下簡單的 Hello World 是如何實現的。那麼此次我就來講說,關於組件的兩個形式。編程

可是在此以前,我以爲仍是有必要簡單的來講一說關於 Dart 語言的一些東西。後端

關於 Dart

Dart 語言是由谷歌公司開發的網絡編程語言,於2011年10月10日發佈。Dart是一個小型的編譯型語言瀏覽器

Dart 主要支持和麪向 3 個不一樣平臺的開發需求:服務器

  • Dart webdev 開發瀏覽器應用。
  • Flutter 開發移動應用。
  • Dart VM 開發腳本或者服務器應用。

Dart 的特性

Dart 吸取了一些後端語言和前端語言的一部分特色。在 Dart 中全部的東西都是對象,function 是對象;String 是對象;Number是對象;null 也是對象。(是否是有內味兒了?)markdown

  • 這是一個強類型的語言,能夠作類型推斷。
  • 一切數據類型都派生自 Object
  • 若無初始化的變量均爲 null 默認值
  • 擁有動態類型、泛型以及運算符重載。
  • 擁有頂級函數 main。
  • 沒有聲明類關鍵字 "public" "private",以 "_" 開頭則表示僅對當前域有效,既是私有的。
  • final 單次聲明,既只可賦值一次,以後再次賦值無效。

Ok,關於 Dart 語言就簡單介紹這點好了。更多的 Dart 語言內容請參考:dart.dev/網絡

State x Widget 繼承關係

在簡單介紹關於 Dart 語言後,就能夠說說 StatelessWidgetStatefulWidget 了。上一篇中說到 StatelessWidget 和 StatefulWidget 均繼承自 Widget,都是 Widget 的抽象類。【傳送門】框架

image.png
(StatelessWidget 的繼承關係)less

image.png
(StatefulWidget 的繼承關係)

從源碼中咱們能夠看出且證明了 StatelessWidgetStatefulWidget繼承自 Widget 且都是 Widget 的抽象類 abstract。

這裏我將他們的關係整理了一下。

image.png
(StatelessWidget 和 StatefulWidget 的繼承關係圖)

如圖所示,而這也從側面證明了 Dart 中全部對象都是 Object

在以前的文章中我也有提到過 StatelessWidgetStatefulWidget 雖然都是 Widget 的抽象類。可是他們之間仍是有區別的,它們分別用於實現不一樣場景下使用的 Widget 組件

State x Widget 有狀態與無狀態

StatelessWidget - 無狀態

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 = '我是新的文字'; // 賦值新文字內容
          },
        )
      ],
    ));
  }
}
複製代碼

結果以下:

image.png
(文字內容並無更新)

即便觸發了按鈕,且對 setText 進行了賦值,可是咱們的 Text 內容依然沒有更新。

StatefulWidget - 有狀態

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('狀態變動文字更新');
            });
          },
        ),
      ]),
    );
  }
}
複製代碼

結果以下:

image.png
(使用 setState 更新內容)

這裏咱們能夠從結果中看到,經過按鈕的觸發調用 setState 來進行狀態的更新從而更新了 Text 的文字內容。

疑問

這時候一些少俠們就不樂意了:「StatefulWidget 用了 setState 來更新內容,StatelessWidget 沒有,不公平!

640.gif

哈哈哈哈,不要緊,那麼咱們就來試一試!我就喜歡你這種勇於發出不一樣聲音的人。

咱們如今繼續使用 StatefulWidget 的代碼,而後直接將繼承對象更新爲 StatelessWidget

image.png

(更改繼承類型爲 StatelessWidget)

那麼咱們來看看結果會是怎麼樣?在命令行中鍵入 R 後耐心等待……

image.png

來來來,讓咱們掌聲送給這幾位勇敢的少俠,喜提滿屏紅。

爲何會這樣?

爲何會這樣呢?由於它們在源碼中的實現是不一樣的。

image.png
(StatelessWidget 源碼部分)

image.png
image.png
(StatefulWidget 源碼部分)

在源碼中 StatelessWidgetStatefulWidget 的實現方式不同。

我能夠簡單翻譯一下。

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


總結

  • 在還不太理解的狀況下,能夠多去嘗試以驗證你的想法。
  • 有時候能夠考慮看看源碼,一些優秀的編程語言或者開源框架在源碼部分都會有良好的註釋內容,它會告訴你它們在這裏作了些什麼。
相關文章
相關標籤/搜索