[ -Flutter漫談篇- ] StatelessWidget Or StatefulWidget

抉擇的條件若是是錯誤的,那麼抉擇的自己沒有任何意義。----張風捷特烈bash

人生最難莫過抉擇,特別是分不清好壞的時候。To be, or not to be, that is a question
在你Flutter中的第一個抉擇也許就是 StatelessWidget Or StatefulWidget
本文就來跟大家說說這兩個傢伙是幹嗎的,有什麼不一樣,該怎麼用。微信


1.描述統一形式化
#define by 張風捷特烈 做用域:本文
[0].用戶打開應用到應用進程結束的過程稱做一次[會話]

[1].具備可視化表現能力的元素,稱爲[顯示元],如一個文字、按鈕、圖片...  
[2].顯示元的一切屬性集稱爲[狀態],如顏色,大小,樣式...  
[3].一個顯示元在一次會話中的全部狀態稱爲[狀態集]  

[4].用戶看到的一屏顯示元組成的集合,稱爲[界面]
[5].一次會話中全部的界面集合,稱爲[UI]
[6].具備改變顯示元狀態的行爲稱爲[事件]
[7].一次會話中全部的事件集合稱爲[事件集]

設:某顯示元的一次會話中[狀態集]爲 S, 令 |S|表示集合元素個數
定義: StatelessWidget ⇔ |S| = 1
定義: StatefulWidget ⇔ |S| > 1
複製代碼

引理1: 狀態(s)決定顯示元(w)的表現。且s與w一一對應,稱爲滿射 f 
記做: w = f(s) 

引理2: 事件(e)能夠改變顯示元狀態(s),每一個e對應狀態,稱爲映射 g
記做: s = g(e)  推論:w = f(g(e))  f與g的合成映射記做F,則 w = F(e)
複製代碼
  • StatelessWidget性質:對於任意e, 有恆定s ⇔ 任意 e,有恆定w

  • StatefulWidget性質:存在e, 使 s 變化

#define endless


1.StatelessWidget : f(x) = 2

若是要顯示下面的界面元,在沒有任何前提的狀況下,選擇StatelessWidget
下面是由四個顯示元構成的界面,每一個顯示元一旦誕生就是不可變的ide

//指定半徑,是否選擇,顏色,邊線色
class ShapeColor extends StatelessWidget {
  ShapeColor(
      {Key key,
      this.radius = 20,
      this.checked = true,
      this.color=Colors.red,
      this.shadowColor=Colors.blue,
      this.elevation=2})
      : super(key: key);
  final double radius; //半徑
  final bool checked; //標記是否被選中
  final Color shadowColor; //顏色
  final Color color; //顏色
  final double elevation; //顏色

  @override
  Widget build(BuildContext context) {
    var shape = Container(
      width: radius,
      height: radius,
      decoration: BoxDecoration(//圓形裝飾線
        color: color ?? Colors.red,
        shape: BoxShape.circle,
        boxShadow: checked
            ? [
                BoxShadow(//陰影
                  color: shadowColor,
                  offset: Offset(0.0, 0.0),
                  spreadRadius: elevation,
                  blurRadius: elevation
                ),
              ]
            : [],
      ),
    );
    return shape;
  }
}
複製代碼

2.StatefulWidget : g(x) = 2x

因爲StatelessWidget自己不可變,但並不意味着它不能借助外界來變
就像 f(x) = 2 是一條不變的橫線。 無論x多麼努力,都不可能擺脫2的無用命運
若是如今有一個g(x) = 2x , 那 g(f(x)) = 4x 。這時f(x)和 g(x)協做完成了4x
StatefulWidget就像是這個g映射,你沒有舞臺,我給你,也能發揮你的價值。post

class ShapeColorRadio extends StatefulWidget {
  ShapeColorRadio({Key key,this.radius = 20,
    this.color=Colors.red,
    this.shadowColor=Colors.blue,
    this.elevation=2}):super(key:key);
  
  final double radius; //半徑
  final Color shadowColor; //顏色
  final Color color; //顏色
  final double elevation; //顏色
  @override
  _ShapeColorRadioState createState() => _ShapeColorRadioState();
}

class _ShapeColorRadioState extends State<ShapeColorRadio> {
  var _checked =false;

  @override
  Widget build(BuildContext context) {

    return GestureDetector(
      onTap: (){
        setState(() {//改變狀態
          _checked=!_checked;
        });
      },
      child: ShapeColor(
        color: widget.color,
        elevation: widget.elevation,
        shadowColor: widget.shadowColor,
        radius: widget.radius,
        checked: _checked,
      ),
    );
  }
}
複製代碼

3.如何抉擇

若是你一開始就意識到須要的是 g(x) = 4x ,你徹底能夠一步到位。但本質上的邏輯是相同的。
就像你吃草莓蛋糕,能夠一口吞,也能夠草莓和蛋糕分開吃,最後都在你肚子裏。
一口吞簡單方便,分開吃你能夠單獨體會草莓的味道,回味和複用。ui

class ShapeColorRadio extends StatefulWidget {
  ShapeColorRadio({Key key,this.radius = 20,
    this.color=Colors.red,
    this.shadowColor=Colors.blue,
    this.elevation=2}):super(key:key);

  final double radius; //半徑
  final Color shadowColor; //顏色
  final Color color; //顏色
  final double elevation; //顏色
  @override
  _ShapeColorRadioState createState() => _ShapeColorRadioState();
}

class _ShapeColorRadioState extends State<ShapeColorRadio> {
  var _checked =false;

  @override
  Widget build(BuildContext context) {
    var shape = Container(
      width: widget.radius,
      height: widget.radius,
      decoration: BoxDecoration(
        //圓形裝飾線
        color: widget.color ?? Colors.red,
        shape: BoxShape.circle,
        boxShadow: _checked
            ? [
          BoxShadow(//陰影
              color: widget.shadowColor,
              offset: Offset(0.0, 0.0),
              spreadRadius: widget.elevation,
              blurRadius: widget.elevation
          ),
        ]
            : [],
      ),
    );
    return GestureDetector(
      onTap: (){
        setState(() {//改變狀態
          _checked=!_checked;
        });
      },
      child: shape,
    );
  }
}
複製代碼

4.StatefulWidget得天獨厚的優點

StatefulWidget得天獨厚的優點在於它有生命週期,initState,didChangeDependencies,didUpdateWidget,reassemble,build,deactivate,dispose。 每一個方法都會在組件相應的狀態回調,這樣看來StatefulWidget更像是一個有生命的東西,而StatelessWidget更像是個死的玩偶。若是你想要去更細粒度地掌控一個組件StatefulWidget是你最佳選擇。this


若是你在Widget中寫了一個不是final的字段,雖然不會崩,但AS小姐姐會抱怨: "TM,說好的在一塊兒,永遠不改變immutable(不可變),你不final是幾個意思。"嚇得我立馬加上final。spa

但有時確實須要有改變的字段怎麼辦?一個字:用StatefulWidget
若是想在組件移除的時候釋放對象怎麼辦:一個字:用StatefulWidget
什麼是用StatelessWidget。f(x) = 2code


5.濫用StatefulWidget-機智如你

有人會說,既然StatefulWidget這麼好,我都用StatefulWidget不就好了嗎?
我反問一句。表達直線 f(x) = 2 。 你會用 f(x) = g(1) 其中g(x) = 2x嗎?
若是不會,那就乖乖地垃圾分類。若是以爲無所謂,那隨你嘍,亂扔垃圾罰得也不是我
食物鏈能量的傳遞效率是逐級遞減的,只要有傳遞,就會有損耗。cdn

abstract class StatelessWidget extends Widget {
  const StatelessWidget({ Key key }) : super(key: key);
  @override
  StatelessElement createElement() => StatelessElement(this);
 considerations.
  @protected
  Widget build(BuildContext context);
}

abstract class StatefulWidget extends Widget {
  const StatefulWidget({ Key key }) : super(key: key);
  @override
  StatefulElement createElement() => StatefulElement(this);
  @protected
  State createState();
}
複製代碼

StatelessWidget依靠StatelessElement建立元素,StatefulElement依靠StatefulElement建立元素,他倆有個共同的爹叫ComponentElement,爺爺是Element。因此他倆是兄弟,那麼既然同一個爹生的,差異咋就這麼大呢?預知後事如何,且聽下回分解。

滿紙荒唐言,一把辛酸淚。都言做者癡,誰解其中味。

本文到此接近尾聲了,若是想快速嚐鮮Flutter,《Flutter七日》會是你的必備佳品;若是想細細探究它,那就跟隨個人腳步,完成一次Flutter之旅。
另外本人有一個Flutter微信交流羣,歡迎小夥伴加入,共同探討Flutter的問題,本人微信號:zdl1994328,期待與你的交流與切磋。

相關文章
相關標籤/搜索