[Flutter必備]-StatefulWidget的打開方式

0.前言

剛接觸Flutter的小伙伴在StatefulWidget控件時會感覺難以接受
本人一開始也是,不過對React的了解讓我很快理解了Flutter的狀態(tài)觀念
本篇就說一下我對StatefulWidget一族的理解,希望可以幫你解決一些疑慮


1.從Slider開始說起

也許你在第一次使用Slider的時候會碰壁,你會發(fā)現(xiàn)它拖不動!
但如果你比較細心可以發(fā)現(xiàn)監(jiān)聽的值是在變化的,這跟Android是不同的

image
var slider = Slider(
  value: 0,
  max: 100,
  min: 0,
  onChanged: (e) {
    print('onChanged:$e');
  },
  onChangeStart: (e) {
    print('onChangeStart:$e');
  },
  onChangeEnd: (e) {
    print('onChangeEnd:$e');
  });
///------主場景-------
var scaffold = Scaffold(
    body: Center(child: slider,)
);
var app = MaterialApp(
  title: 'Flutter Demo',
  theme: ThemeData(
    primarySwatch: Colors.blue,
  ),
  home: scaffold,
);
void main() => runApp(app);

2:如何讓Slider有用武之地

現(xiàn)在回想一下Android怎么改變屬性

在Android里控件修改其屬性可以直接`對象.set屬性`來設(shè)置  
但在FLutter里你會奇怪的發(fā)現(xiàn):當你`slider.value=20;`時會報錯  
這真是讓人不爽漓柑,對象更改屬性不是天經(jīng)地義嗎?但Flutter說:對不起镊折,你不能

這讓我恍然大悟焙矛,為什么Widget源碼里說所有的組件都是恒定的,它只是對元素的描述
組件的屬性無法被改變因為屬性都是final修飾的,既然無法修改,那又為什么會有狀態(tài)一說?

其實恒定和變化是相對的,多個恒定的狀態(tài)的連續(xù)重演就會產(chǎn)生動態(tài)效果  
就像電影也只是圖片的疊加缚去,一張圖片是恒定的,它也只是用像素對一個場景的色彩信息進行的描述
但多個恒定的照片連續(xù)播放時就會產(chǎn)生動態(tài)的效果驶冒,讓我們感覺里面的人是活的件相,世界是運動的
這其中化腐朽為神奇的關(guān)鍵就是如何持續(xù)渲染,就像電影如何連續(xù)一幀幀的播放  
這時狀態(tài)類中的setState()應(yīng)聲而出,交給我,只要喊我一聲财边,我就為你們更新狀態(tài)  

這和React是如出一轍的,這種方式在我看來是非常優(yōu)雅的肌括。對象更改自身屬性與之相比就笨重了許多
前者可以通過一個狀態(tài)來表述、更新酣难、修改自己谍夭,而后者只是能通過他本身來親力親為


3:如何正確打開Slider

上面說需要狀態(tài),那就需要一個StatefulWidget,如下:有一個私有的變量_value,
在Slider拖動的過程中執(zhí)行_render方法進行渲染,在渲染時先將Slider的值給_value
在setState方法調(diào)用之后憨募,build將會重新執(zhí)行紧索,那么Slider的值就會使用_value,從而實現(xiàn)狀態(tài)的更新

image
class TextSlider extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _TextSliderState();
}

class _TextSliderState extends State<TextSlider> {
  double _value = 0;

  @override
  Widget build(BuildContext context) {
    var show = _buildSlider(_value);
    return show;
  }

  _buildSlider(double value) {
    var slider = Slider(
      value: value,
      max: 100,
      min: 0,
      onChanged: (e) {
        print('onChanged:$e');
        _render();
      },
      onChangeStart: (e) {
        print('onChangeStart:$e');
      },
      onChangeEnd: (e) {
        print('onChangeEnd:$e');
      },
    );
    
    return slider;
  }

  _render(double value) {
    _value = value;
    setState(() {});
  }
}

4:這樣的優(yōu)勢

可能你會覺得只是使用一個Slider,還要寫個類菜谣,未免有點小題大做

麻煩必然有其價值,簡單必然有其局限珠漂。這便是宇宙的平衡晚缩。
一開始學編程時,定義了一個Circle類,可以用對象來算面積,
當時就想媳危,這有必要嗎荞彼,一個方法就搞定了啊,是不是有點小題大做。
之后漸漸發(fā)現(xiàn)面向?qū)ο蟮镊攘?我不知你們對萬物皆對象如何理解,這里說一下我的看法:

萬物皆對象并不是站在人類的角度說世間的實體都是對象,而是站在另一個維度  
一個應(yīng)用便是一個小世界,里面有眾多對象相互協(xié)調(diào)合作,來完成應(yīng)用的功能待笑。
這個小世界中的一切皆為對象鸣皂。Coder需要管理這些對象的樣貌,生死,家族關(guān)系滋觉,社交關(guān)系以及工作流程签夭。
而對象的產(chǎn)生是要靠類來創(chuàng)建,所以類是至關(guān)重要的,其創(chuàng)建需要站在統(tǒng)領(lǐng)世界的上帝視角。
所以編程對我而言就是在創(chuàng)世,而我便是創(chuàng)世神,思想的高度可以讓你的眼前有一個完全不一樣的世界椎侠。  

話說回來,為什么要這樣做呢?

三個詞: 易復用第租、好維護、可拓展

這三個詞會伴隨Coder的編程生涯我纪,如何讓自己創(chuàng)造的世界更好的運作慎宾,是我們殫精竭慮的  
從設(shè)計模式到數(shù)據(jù)結(jié)構(gòu),從編碼到重構(gòu),我們努力調(diào)整維持這個世界的秩序,讓它們脫離bug的魔爪  
面向過程中的零星代碼通過一個類的整合浅悉,形成一個創(chuàng)物的藍圖趟据,用來召喚(new)對象

不知你是否有所感覺,Android中控件用起來是比較卡手的,總的來說就是太難復用术健,代碼零星  
比如汹碱,一個Slider滑動時Text跟隨顯示,在Activity中創(chuàng)建兩個對象,讓兩者協(xié)調(diào),
一兩個還好荞估,多了就會感覺分布零散咳促,而且冗余難看,為此自定義一個View?還是饒了我吧  
Android中控件的組合感覺很笨重,就連點擊一下還有先找個id,但我也此心不改勘伺,未之樂此不疲,沒辦法跪腹,這就是愛  

玩前端接觸React的時候我就像尋到新歡,React的組件非常吸引我,靈活,簡潔飞醉,優(yōu)雅  
再看Android,恨鐵不成鋼冲茸。直到現(xiàn)在Flutter出現(xiàn)了,它帶著React的風采出現(xiàn)在移動端,甚至全端  
Flutter中對于界面感覺非常友好,雖然剛來時一堆括號的嵌套讓人難以適應(yīng)缅帘,但漸漸你會發(fā)現(xiàn)他的美  
Widget認為界面上的元素都成為組件,使用簡單轴术,非常容易復用。

5:組件間的組合

看一下Flutter中組合Slider和Text是多么簡潔,只要添加一些就行了
如果Android自定義這樣的控件钦无,需要自定義ViewGroup,將兩個組件拼合
所以Flutter中組件的拼合是非常方便的,使用也很簡潔

image
---->[_TextSliderState#build]----
var show = Column(
  mainAxisSize: MainAxisSize.min,
  children: <Widget>[_buildText(_value), _buildSlider(_value)],
);

_buildText(double value) {
  return Text(
    value.toStringAsFixed(2),//保留兩位有效數(shù)字
    style: TextStyle(fontSize: 20),
  );
}

6:狀態(tài)的魅力

比如需要象下面這樣滑動到50之后復選框選中逗栽,當點擊復選框清零
放在Android中想想都覺得凌亂,但自定義控件有麻煩,就像爐石起手全是高費的卡手心情
在Flutter中你想怎么封怎么封,只要狀態(tài)改變铃诬,我就給你響應(yīng)祭陷,這是很優(yōu)雅的。

image
---->[_TextSliderState#build]----
var show = Column(
  mainAxisSize: MainAxisSize.min,
  children: <Widget>[
    Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        _buildCheckBox(_value),
        _buildText(_value),
      ],
    ),
    _buildSlider(_value)
  ],);

_buildCheckBox(double value) {
  var checked = value > 50;
  return Checkbox(
    value: checked,
    onChanged: (bool) {
      _render(0);
    },
  );
}

只是修改嵌套是有點小麻煩趣席,如果有類似wedgetChild.father=wedgetFather這樣的認干爹就好了


7:關(guān)于修改

你也可以很容易的通過布局容器修改組件的相對位置

image
var show = Row(
  mainAxisSize: MainAxisSize.min,
  crossAxisAlignment: CrossAxisAlignment.center,
  children: <Widget>[
    Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
        _buildCheckBox(_value),
        _buildText(_value),
      ],
    ),
    _buildSlider(_value)
  ],
);

8.關(guān)于監(jiān)聽

要知道你定義的每個組件都是可以拿去復用的兵志,和Flutter原生組件地位是一樣的

我們在需要拖動的監(jiān)聽,那么就需要在渲染之前進行回調(diào),讓使用者可以接受回參

class TextSlider extends StatefulWidget {

  ValueChanged onChanged;
  TextSlider({this.onChanged});

  @override
  State<StatefulWidget> createState() => _TextSliderState();
}

typedef ValueChanged = void Function(double value);


  _render(double value) {
    if(widget.onChanged!=null){
      widget.onChanged(value);
    }
    _value = value;
    print(value);
    setState(() {});  }

9.復用的靈活

一個組件類形成之后宣肚,復用就非常方便了想罕,如果Android實現(xiàn)下面的拖動更新
邏輯上不復雜,但是代碼將會非常多,因為Android很難復用組件霉涨,只能一個個來按价。
Flutter中實現(xiàn)起來就很簡潔,甚至監(jiān)聽也非常方便笙瑟。比如下面的:
短短幾行代碼就實現(xiàn)了四個的各自拖動監(jiān)聽,這是笨重的xml所不能及的

image
var a = (a) {
  print("a:$a");
};

var b = (b) {
  print("b:$b");
};

var c = (c) {
  print("c:$c");
};

var d = (d) {
  print("d:$d");
};

var childs= [a,b,c,d].map((fun){
  return SizedBox.fromSize(size: Size(250, 100), child: TextSlider(onChanged: fun,),);
}).toList();

var scaffold = Scaffold(
    body: Center(child: Wrap(children:childs,),)
);

10.小結(jié)

Flutter針對界面是非常友好的楼镐,它可以作為Android視圖很好地補充。
更不用說Flutter強大的跨平臺能力,它已成為一顆新星,正冉冉升起往枷。
你還在等什么,見證一下Flutter的魅力吧框产,相信你會喜歡上它的。


結(jié)語

本文到此接近尾聲了错洁,如果想快速嘗鮮Flutter秉宿,《Flutter七日》會是你的必備佳品;如果想細細探究它,那就跟隨我的腳步,完成一次Flutter之旅屯碴。
另外本人有一個Flutter微信交流群描睦,歡迎小伙伴加入,共同探討Flutter的問題导而,本人微信號:zdl1994328忱叭,期待與你的交流與切磋。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嗡载,一起剝皮案震驚了整個濱河市窑多,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌洼滚,老刑警劉巖埂息,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異遥巴,居然都是意外死亡千康,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門铲掐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拾弃,“玉大人,你說我怎么就攤上這事摆霉『来唬” “怎么了奔坟?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長搭盾。 經(jīng)常有香客問我咳秉,道長,這世上最難降的妖魔是什么鸯隅? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任澜建,我火速辦了婚禮,結(jié)果婚禮上蝌以,老公的妹妹穿的比我還像新娘炕舵。我一直安慰自己,他們只是感情好跟畅,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布咽筋。 她就那樣靜靜地躺著,像睡著了一般徊件。 火紅的嫁衣襯著肌膚如雪晤硕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天庇忌,我揣著相機與錄音舞箍,去河邊找鬼。 笑死皆疹,一個胖子當著我的面吹牛疏橄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播略就,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼捎迫,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了表牢?” 一聲冷哼從身側(cè)響起窄绒,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎崔兴,沒想到半個月后彰导,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡敲茄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年位谋,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片堰燎。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡掏父,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出秆剪,到底是詐尸還是另有隱情赊淑,我是刑警寧澤爵政,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站陶缺,受9級特大地震影響茂卦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜组哩,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望处渣。 院中可真熱鬧伶贰,春花似錦、人聲如沸罐栈。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽荠诬。三九已至琅翻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間柑贞,已是汗流浹背方椎。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留钧嘶,地道東北人棠众。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像有决,于是被迫代替她去往敵國和親闸拿。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內(nèi)容