抉擇的條件若是是錯誤的,那麼抉擇的自己沒有任何意義。----張風捷特烈
bash
人生最難莫過抉擇,特別是分不清好壞的時候。
To be, or not to be, that is a question
在你Flutter中的第一個抉擇也許就是StatelessWidget Or StatefulWidget
本文就來跟大家說說這兩個傢伙是幹嗎的,有什麼不一樣,該怎麼用。微信
#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)
複製代碼
對於任意e, 有恆定s ⇔ 任意 e,有恆定w
存在e, 使 s 變化
#define end
less
若是要顯示下面的界面元,在沒有任何前提的狀況下,選擇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;
}
}
複製代碼
因爲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,
),
);
}
}
複製代碼
若是你一開始就意識到須要的是 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,
);
}
}
複製代碼
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
有人會說,既然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
,期待與你的交流與切磋。