Flutter學(xué)習(xí)筆記(三)-- 事件交互和State管理

先來看看準(zhǔn)備界面:
image.png

目標(biāo)是修改圖中紅色實(shí)線框中的喜歡和不喜歡的五角星的修改,以及數(shù)字的修改。
在修改之前,有必要先了解一些相關(guān)的信息秽褒。

知識點(diǎn)

前面簡單的提到過壶硅,有些Widget是Statful(有狀態(tài)的),而其他的一些是Stateless(無狀態(tài)的)销斟。比如繼承自StatefulWidget的有Checkbox庐椒、Radio、Slider蚂踊、Form等约谈,這些Widget用戶都是可以做一些交互的,同樣的繼承自StatelessWidget的Widget有Text、Icon等犁钟。有狀態(tài)和無狀態(tài)的主要區(qū)別在于:有狀態(tài)的Widget在其內(nèi)部都有一個(gè)state用來標(biāo)記是否發(fā)生了變化棱诱,然后調(diào)用setState()方法來更新自己。

創(chuàng)建Stateful Widget

關(guān)鍵點(diǎn):
1涝动、創(chuàng)建一個(gè)Stateful Widget需要兩個(gè)類迈勋,分別繼承自StateFulWidget和State
2、state對象包含了widget的state和widget的build()方法
3醋粟、當(dāng)widget的state改變了的時(shí)候靡菇,state對象會調(diào)用setState()方法,告訴框架去重繪widget米愿。

到這里厦凤,其實(shí)也可以明白,只有Stateful的Widget才能修改其內(nèi)容育苟,所以要想實(shí)現(xiàn)上面的目標(biāo)较鼓,必須將原來的Icon和Text這兩個(gè)Stateless的Widget替換成Stateful類型的Widget。
所以我們必須實(shí)現(xiàn)兩個(gè)Stateful類型的Widget违柏,沒個(gè)Widget都應(yīng)該包含下面兩個(gè)點(diǎn):

  • 一個(gè)StatefulWidget的子類博烂,并且實(shí)現(xiàn)了createState()方法;
  • 一個(gè)State的子類漱竖,并且實(shí)現(xiàn)了build()方法脖母。
如果足夠留意,會發(fā)現(xiàn)主函數(shù)里就是一個(gè)StatefulWidget闲孤。

代碼

搞清楚了上面的,然后結(jié)合官方文檔烤礁,基礎(chǔ)的架子如下:

class FavoriteWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => new _FavoriteWidgetState();
}

class _FavoriteWidgetState extends State {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return null;
  }
}

完整的代碼如下所示:

class FavoriteWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => new _FavoriteWidgetState();
}

class _FavoriteWidgetState extends State {
  var _isFavorited = true;  // 是否喜歡
  var _favoriteCount = 41;  // 喜歡個(gè)數(shù)
  _toggleFavorite() {
    setState((){
      if(_isFavorited) {
        _favoriteCount -= 1;
      } else {
        _favoriteCount += 1;
      }
      _isFavorited = !_isFavorited;
    });
  }
  @override
  Widget build(BuildContext context) {
    return new Row(
      mainAxisAlignment: MainAxisAlignment.center,
      mainAxisSize: MainAxisSize.min,
      children: <Widget>[
        new Container(
          padding: const EdgeInsets.all(0.0),
          margin: const EdgeInsets.all(0.0),
          child: new IconButton(icon: (_isFavorited ? new Icon(Icons.star) : new Icon(Icons.star_border)), onPressed: _toggleFavorite, color: Colors.red),
        ),
        new SizedBox(
          width: 18.0,
          child: new Container(
            child: new Text("$_favoriteCount"),
          ),
        )
      ],
    );
  }
}
注意:為什么上面的Text要用SizedBox包裹起來呢讼积?如果不寫width可以嗎?(主要是為了解決跳動(dòng)的問題)

最后脚仔,拿這個(gè)widget去替換原來代碼的相應(yīng)位置的內(nèi)容勤众。

上面說到的對state的管理是交給了FavoriteWidget,即當(dāng)前Widget去管理鲤脏,而實(shí)際情況中们颜,對state的管理可以有很多種辦法吕朵,接下來會慢慢學(xué)習(xí)!

狀態(tài)管理

最通用的有三種方式:
1窥突、Widget自己管理State
2努溃、父類管理State
3、混合管理
那么如何確定使用哪種管理方式呢阻问,這里有兩個(gè)建議:
1梧税、如果是和用戶數(shù)據(jù)相關(guān)的,建議用父類來管理
2称近、如果是為了審美第队,比如動(dòng)畫,建議Widget自己管理

1刨秆、自己管理State

這種方式比較直接凳谦,也比較好理解,因?yàn)槎际窃谧约旱沫h(huán)境下處理衡未,所以直接貼出代碼:

class _TapboxA extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => new _TapboxAState();
}

class _TapboxAState extends State<_TapboxA> {
  var _active = false;
  _handleTap() {
    setState(() {
      _active = !_active;
    });
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new GestureDetector(
      onTap: _handleTap,
      child: new Container(
        width: 200.0,
        height: 200.0,
        color: _active ? Colors.lightGreen[700] : Colors.grey[600],
//        decoration: new BoxDecoration(
//          color: _active ? Colors.lightGreen[700] : Colors.grey[600]
//        ),
        child: new Center(
          child: new Text(
            _active ? 'Active' : 'Inactive',
            style: new TextStyle(fontSize: 32.0, color: Colors.white),
          ),
        ),
      ),
    );
  }
}

2尸执、父控件控制State

該控制的核心在于:回調(diào)。父控件通過傳遞參數(shù)控制子控件的展示眠屎,子控件通過函數(shù)的回調(diào)剔交,改變父控件的值,然后父控件調(diào)用setState()方法再反饋到具體的子控件的展示上改衩。
具體的代碼如下:

class _TapBoxB extends StatelessWidget {   // 此時(shí)子控件是Stateless的 
//  var active = false;
  final active;
  final ValueChanged<bool> onChanged;
  _TapBoxB({Key key, this.active: false, @required this.onChanged})
      : super(key: key);
  void _handleTap() {
    onChanged(!active);
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new GestureDetector(
      onTap: _handleTap,
      child: new Container(
        child: new Center(
          child: new Text(
            active ? 'Active' : 'Inactive',
            style: new TextStyle(fontSize: 32.0, color: Colors.white),
          ),
        ),
        width: 200.0,
        height: 200.0,
        decoration: new BoxDecoration(
            color: active ? Colors.lightGreen[700] : Colors.grey[600]),
      ),
    );
  }
}

class ParentWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return new _ParentWidgetState();
  }
}

class _ParentWidgetState extends State<ParentWidget> {
  var _active = false;
  _handleTapboxChanged(bool newValue) {
    setState(() {
      _active = newValue;
    });
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new Container(
      child: new _TapBoxB(
        active: _active,   // 傳值
        onChanged: _handleTapboxChanged,  // 回調(diào)岖常,用于觸發(fā)回調(diào)
      ),
    );
  }
}

3、混合管理

通俗講葫督,就是上面兩種的柔和竭鞍,父控件控制一些自己需要的State,子控件控制一些自己的State橄镜。
代碼如下:

class _ParentWidget extends StatefulWidget {
  bool active = false;
  @override
  State<StatefulWidget> createState() => new _ParentWidgetState();
}

class _ParentWidgetState extends State<_ParentWidget> {

  void _handleTapboxChanged(bool newValue) {
    setState(() {
      widget.active = newValue;
    });
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new Container(
      child: new TapboxC(onChanged: _handleTapboxChanged, active: widget.active),
        );
  }
}

class TapboxC extends StatefulWidget {
  final bool _active;
  bool _highlight = false;
  final ValueChanged<bool> onChanged;
  TapboxC({Key key, bool active, @required this.onChanged})
      :this._active = active, super(key: key) { }
  @override
  State<StatefulWidget> createState() => new _TapboxCState();
}

class _TapboxCState extends State<TapboxC> {

  void _handleTap() {
    widget.onChanged(!widget._active);
  }

  void _handleTapDown(TapDownDetails details) {
    setState((){
      widget._highlight = true;
    });
  }

  void _handleTapUp(TapUpDetails details) {
    setState((){
      widget._highlight = false;
    });
  }

  void _handleTapCancel(){
    setState((){
      widget._highlight = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new GestureDetector(
      onTap: _handleTap,
      onTapDown: _handleTapDown,
      onTapUp: _handleTapUp,
      onTapCancel: _handleTapCancel,
      child: new Container(
        width: 200.0,
        height: 200.0,
        decoration: new BoxDecoration(
          color: widget._active ? Colors.lightGreen[700] : Colors.grey[600],
          border: widget._highlight
              ? new Border.all(color: Colors.teal[700], width: 10.0)
              : null,
        ),
      ),
    );
  }
}

這里與官方的代碼相比偎快,我把所有的和state相關(guān)的都放到了Widget類里。(但是洽胶,其實(shí)這么寫是有問題的晒夹,可以自己想想,將在下一節(jié)分析)

至此姊氓,F(xiàn)lutter里的State的管理和事件交互也做了簡單的了解了丐怯,對于我來說,還是不甚了解翔横。重要的還在于多看多寫读跷。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市禾唁,隨后出現(xiàn)的幾起案子效览,更是在濱河造成了極大的恐慌无切,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,651評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丐枉,死亡現(xiàn)場離奇詭異哆键,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)矛洞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評論 3 392
  • 文/潘曉璐 我一進(jìn)店門洼哎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人沼本,你說我怎么就攤上這事噩峦。” “怎么了抽兆?”我有些...
    開封第一講書人閱讀 162,931評論 0 353
  • 文/不壞的土叔 我叫張陵识补,是天一觀的道長。 經(jīng)常有香客問我辫红,道長凭涂,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,218評論 1 292
  • 正文 為了忘掉前任贴妻,我火速辦了婚禮切油,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘名惩。我一直安慰自己澎胡,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評論 6 388
  • 文/花漫 我一把揭開白布娩鹉。 她就那樣靜靜地躺著攻谁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪弯予。 梳的紋絲不亂的頭發(fā)上戚宦,一...
    開封第一講書人閱讀 51,198評論 1 299
  • 那天,我揣著相機(jī)與錄音锈嫩,去河邊找鬼受楼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛呼寸,可吹牛的內(nèi)容都是我干的那槽。 我是一名探鬼主播,決...
    沈念sama閱讀 40,084評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼等舔,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了糟趾?” 一聲冷哼從身側(cè)響起慌植,我...
    開封第一講書人閱讀 38,926評論 0 274
  • 序言:老撾萬榮一對情侶失蹤甚牲,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后蝶柿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體丈钙,經(jīng)...
    沈念sama閱讀 45,341評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評論 2 333
  • 正文 我和宋清朗相戀三年交汤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了雏赦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,731評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡芙扎,死狀恐怖星岗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情戒洼,我是刑警寧澤俏橘,帶...
    沈念sama閱讀 35,430評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站圈浇,受9級特大地震影響寥掐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜磷蜀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評論 3 326
  • 文/蒙蒙 一召耘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧褐隆,春花似錦污它、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至虫埂,卻和暖如春祥山,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背掉伏。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評論 1 269
  • 我被黑心中介騙來泰國打工缝呕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人斧散。 一個(gè)月前我還...
    沈念sama閱讀 47,743評論 2 368
  • 正文 我出身青樓供常,卻偏偏與公主長得像,于是被迫代替她去往敵國和親鸡捐。 傳聞我的和親對象是個(gè)殘疾皇子栈暇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評論 2 354

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

  • 個(gè)人筆記, 轉(zhuǎn)載請注明轉(zhuǎn)載自 szhshp的第三邊境研究所 Refs and the DOM In the t...
    szhielelp閱讀 1,474評論 0 1
  • 前面提過react中的state和props是react組件中的兩大部分,有很多人分不清state和props箍镜,這...
    DCbryant閱讀 17,984評論 0 11
  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個(gè)線程源祈,因...
    小菜c閱讀 6,402評論 0 17
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,080評論 25 707
  • 頑石溪流 經(jīng)歷歲月的手 天睹蒼顏 美麗已流走 嫵媚嬌艷的你 心中開滿愛情豆 誘人的芬芳 馥郁了本已被人們 打入冷宮...
    美麗天空一閱讀 507評論 32 69