flutter Sate 通過widget.xxx 獲取StatefulWidget參數(shù)值之坑

Sate獲取StatefulWidget參數(shù)值常見的兩種方式

1铡原、StatefulWidget傳參給State庆尘,在Sate直接使用StatefulWidget傳來的參數(shù)值,如下:

class TestStatefulWidget extends StatefulWidget {
  //參數(shù) 
  final String _xxx;

  TestStatefulWidget(this._xxx);

  @override
  _TestStatefulWidgetState createState() => _TestStatefulWidgetState(this._xxx);
}

class _TestStatefulWidgetState extends State<TestStatefulWidget> {
  final _xxx;

  _TestStatefulWidgetState(this._xxx);

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text(_xxx), //直接使用StatefulWidget傳來的參數(shù)值
    );
  }
}

2、StatefulWidget不傳參給State,在Sate通過widget.xxx獲取StatefulWidget的參數(shù)值拐云,如下:

class TestStatefulWidget extends StatefulWidget {
  //參數(shù)
  final String _xxx;

  TestStatefulWidget(this._xxx);

  @override
  _TestStatefulWidgetState createState() => _TestStatefulWidgetState();
}

class _TestStatefulWidgetState extends State<TestStatefulWidget> {
  _TestStatefulWidgetState();

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text(widget._xxx), //通過widget獲取StatefulWidget參數(shù)值
    );
  }
}

Sate通過widget.xxx獲取StatefulWidget參數(shù)值之坑

上面兩種獲取參值方式的差別在于StatefulWidget有沒有將參數(shù)直接傳給State,Sate是否通過widget.xxx獲取StatefulWidget參數(shù)值近她;
下面通過實例來演示這兩種獲取參數(shù)值的差別慨丐,如下:

class StatefulWidgetParamPage extends StatefulWidget {
  final String title;

  StatefulWidgetParamPage({Key key, this.title}) : super(key: key);

  @override
  _StatefulWidgetParamPageState createState() =>
      _StatefulWidgetParamPageState();
}

class _StatefulWidgetParamPageState extends State<StatefulWidgetParamPage> {
  int i;

  @override
  void initState() {
    super.initState();
    i = 0;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Container(
          alignment: Alignment.center,
          width: double.infinity,
          height: double.infinity,
          child: Column(
            children: <Widget>[
              TestWidgetA(
                  TestModel(
                    'WidgetA參數(shù):',
                  ),
                  i.toString()),
              TestWidgetB(TestModel('WidgetB參數(shù):'), i.toString()),
              RaisedButton(
                  onPressed: () {
                    i++;
                    setState(() {});
                  },
                  child: Text('值增加刷新')),
              RaisedButton(
                  onPressed: () {
                    i++;
                  },
                  child: Text('值增加不刷新')),
              RaisedButton(
                  onPressed: () {
                    setState(() {});
                  },
                  child: Text('只刷新')),
            ],
          )),
    );
  }
}

class TestModel {
  String title;
  dynamic value;

  TestModel(
    this.title,
  ) {
    var r = new Random();
    value = r.nextInt(1000); //用于區(qū)分對象是否有重新創(chuàng)建,對象重新創(chuàng)建泄私,值會變化
  }

  @override
  String toString() {
    return '$title  自定義對象${value ?? ''}';
  }
}

class TestWidgetA extends StatefulWidget {
  final TestModel model;
  final String value;

  TestWidgetA(this.model, this.value);

  @override
  _TestWidgetAState createState() => _TestWidgetAState();
}

class _TestWidgetAState extends State<TestWidgetA> {
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      child: Container(
        alignment: Alignment.center,
        child: Text(
            '${widget?.model?.toString()}    change value=${widget?.value}\ncontext=$context\n'), //展示傳參數(shù)據(jù) 值隨刷新變
      ),
      onTap: () {
        print(
            '${widget?.model?.toString()}    change value=${widget?.value}\ncontext=$context\n'); //值不變,刷新后widget重新創(chuàng)建,值才變
        /*setState(() {//內部刷新

        });*/
      },
    );
  }
}

class TestWidgetB extends StatefulWidget {
  final TestModel model;
  final String value;

  TestWidgetB(this.model, this.value);

  @override
  _TestWidgetBState createState() => _TestWidgetBState(this.model, this.value);
}

class _TestWidgetBState extends State<TestWidgetB> {
  final TestModel model;
  final String value;

  _TestWidgetBState(this.model, this.value);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      child: Container(
        alignment: Alignment.center,
        child: Text(
            '${model?.toString()}    change value=$value\ncontext=$context\n'), //展示傳參數(shù)據(jù)  值不隨刷新變
      ),
      onTap: () {
        print(
            '${model?.toString()}    change value=$value\ncontext=$context\n'); //值不隨刷新變
        /*setState(() {//內部刷新

        });*/
      },
    );
  }
}

上面代碼比較多晌端,可以先不看捅暴,先看下面的實例效果或自行跑demo,不懂再來看代碼和代碼說明
代碼說明:

  • 上面代碼通過TestWidgetA咧纠、TestWidgetB兩個StatefulWidget來展示Sate獲取StatefulWidget參數(shù)值不同方式帶來的不同效果蓬痒;
  • TestWidgetA:StatefulWidget不傳參給State,在Sate通過widget.xxx獲取StatefulWidget的參數(shù)值漆羔;
  • TestWidgetB:StatefulWidget傳參給State梧奢,在Sate直接使用StatefulWidget傳來的參數(shù)值;
  • TestWidgetA演痒、TestWidgetB參數(shù)值有:自定義對象TestModel亲轨,外部計數(shù)值;
  • TestWidgetA鸟顺、TestWidgetB除State獲取StatefulWidget參數(shù)值方式不一樣惦蚊,其它都一樣,同時展示StatefulWidget參數(shù)值:自定義對象讯嫂、外部計數(shù)參數(shù)值蹦锋;
  • 自定義對象TestModel:
    1、自定義對象TestModel欧芽,在構造方法初始化里用隨機數(shù)賦值莉掂,可通過觀察隨機數(shù)值有沒有變化來判斷自定義對象有沒有重新創(chuàng)建
    2千扔、自定義對象TestModel作為TestWidgetA憎妙、TestWidgetB兩個StatefulWidget的參數(shù),并且自定義對象TestModel是直接實例化傳給widgetTestWidgetA昏鹃、TestWidgetB作為參數(shù)的;
  • 外部計數(shù)值尚氛,用于觀察外部值變化 ,Sate獲取StatefulWidget參數(shù)值是否會跟著變化洞渤;
  • TestWidgetA阅嘶、TestWidgetB展示各自的context是為了說明各自的State沒重新創(chuàng)建,上面例子不會引起TestWidgetA和TestWidgetB各自Sate的重新創(chuàng)建载迄;
  • 三個按鍵功能分別是: 外部計數(shù)值增加并刷新界面讯柔、 外部計數(shù)值增加不刷新界面、只刷新界面护昧;
  • 還有TestWidgetA魂迄、TestWidgetB本身的點擊事件,點擊在log打印惋耙,可實時看到傳參值捣炬,分為內部刷新和內部不刷新兩種熊昌;

外部計數(shù)值增加增加并刷新界面效果:

外部計數(shù)值增加并刷新界面效果.gif

效果說明:

  • 界面刷新時,每刷新一次湿酸,TestWidgetA(Sate 通過widget.xxx獲取StatefulWidget參數(shù)值)的自定義對象參數(shù)值發(fā)生了重新創(chuàng)建婿屹,同時外面?zhèn)鱽淼膮?shù)值隨著外面值的變化而變化;
  • 界面刷新時推溃,TestWidgetB(Sate 沒有通過widget.xxx獲取StatefulWidget參數(shù)值)的自定義對象參數(shù)值沒有發(fā)生重新創(chuàng)建昂利,外面?zhèn)鱽淼膮?shù)值也沒有隨著外面值的變化而變化,也就是TestWidgetB參數(shù)值沒有發(fā)生變化铁坎;

外部計數(shù)值增加不刷新界面效果:

外部計數(shù)值增加不刷新界面效果.gif

效果說明:

  • 只是值增加時蜂奸,TestWidgetA、TestWidgetB的自定義對象參數(shù)沒有發(fā)生重新創(chuàng)建硬萍,外面?zhèn)鱽淼膮?shù)值也沒有隨著外面值的變化而變化扩所;
  • 再刷新時,TestWidgetA(Sate 通過widget.xxx獲取StatefulWidget參數(shù)值)的自定義對象參數(shù)值馬上發(fā)生了重新創(chuàng)建襟铭,同時外面?zhèn)鱽淼膮?shù)值隨著外面值的變化而變化碌奉;TestWidgetB(Sate 沒有通過widget.xxx獲取StatefulWidget參數(shù)值)參數(shù)值沒有發(fā)生變化;

只刷新界面效果:

只刷新界面效果.gif

效果說明:

  • 只刷新界面時寒砖,TestWidgetA(Sate 通過widget.xxx獲取StatefulWidget參數(shù)值)的自定義對象參數(shù)值發(fā)生了重新創(chuàng)建赐劣;
  • TestWidgetB(Sate 沒有通過widget.xxx獲取StatefulWidget參數(shù)值)參數(shù)值不會發(fā)生變化;

不刷新哩都,連續(xù)點擊獲取實時參數(shù)值效果:

連續(xù)點擊獲取實時參數(shù)值效果.png

效果說明:

  • 不刷新魁兼,實時獲取TestWidgetA、TestWidgetB參數(shù)值漠嵌,TestWidgetA咐汞、TestWidgetB參數(shù)值都不會發(fā)生變化;

內部刷新儒鹿,連續(xù)點擊獲取實時參數(shù)值效果:

內部刷新化撕,連續(xù)點擊獲取實時參數(shù)值效果.png

效果說明:

  • 內部刷新,實時獲取TestWidgetA约炎、TestWidgetB參數(shù)植阴,TestWidgetA、TestWidgetB參數(shù)都不會發(fā)生變化圾浅;

總結

StatefulWidget傳參給State掠手,在Sate直接使用StatefulWidget傳來的參數(shù)值:

  • 無論StatefulWidget內部刷新界面、外部刷新界面狸捕,外部參數(shù)值變化喷鸽,在Sate直接獲取StatefulWidget的參數(shù)值都不會改變;

StatefulWidget不傳參給State灸拍,在Sate通過widget.xxx獲取StatefulWidget傳來的參數(shù)值:

  • StatefulWidget內部刷新界面做祝,外面值變化時砾省,在Sate通過widget.xxx獲取參數(shù)值不會變化;
  • 外部界面刷新混槐,在Sate通過widget.xxx獲取StatefulWidget的參數(shù)值隨外面值變化而變化纯蛾;如果自定義對象直接實例化作為StatefulWidget參數(shù),自定義對象參數(shù)值會隨刷新而發(fā)生重新創(chuàng)建纵隔,這點需要重點留意,有可能界面刷新炮姨,自定義對象定義里的值就變成初始化的值了捌刮。

原因分析

1、外部界面刷新:

  • 外部界面刷新時舒岸,Sate里的widget發(fā)生了重新創(chuàng)建
    對于StatefulWidget绅作,Sate和Widget是分離的,widget是一個臨時配置對象蛾派,外部界面刷新時俄认,Sate里的widget會發(fā)生重新創(chuàng)建初始化,widget重新創(chuàng)建初始化洪乍,必會重新執(zhí)行StatefulWidget的構造方法眯杏,StatefulWidget的構造方法重新構建,StatefulWidget的構造方法里的參數(shù)必會跟著重新初始化傳入壳澳,所以在Sate通過widget.xxx獲取StatefulWidget的參數(shù)值隨外部刷新而變化岂贩;
  • 外部界面刷新時,Sate沒有發(fā)生重新創(chuàng)建
    由于外部界面刷新時巷波,Sate沒有發(fā)生重新創(chuàng)建萎津,StatefulWidget將參數(shù)傳給State,也就是拷貝了一份參數(shù)值給Sate抹镊,所以即使widget發(fā)生了重新創(chuàng)建锉屈,Sate獲取的到StatefulWidget的參數(shù)值還是最開始StatefulWidget拷貝的參數(shù)值,沒有變化垮耳;

2颈渊、StatefulWidget內部刷新:

  • StatefulWidget內部刷新時,Sate和widget都沒有發(fā)生重新創(chuàng)建氨菇,所以無論Sate是否通過widget.xxx獲取StatefulWidget傳來的參數(shù)值儡炼,都沒有變化;

溫馨提示:源碼里大多都是通過widget.xxx來獲取StatefulWidget參數(shù)值查蓉,所以并不是說widget.xxx不可取乌询,這兩種方式各有優(yōu)劣勢,用哪一種根據(jù)自己的業(yè)務進行取舍豌研,文章主要是為了說明Sate 通過widget.xxx 獲取StatefulWidget參數(shù)值需要注意參數(shù)值可能隨外部環(huán)境變化而會變化妹田。

demo傳送門

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末唬党,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子鬼佣,更是在濱河造成了極大的恐慌驶拱,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晶衷,死亡現(xiàn)場離奇詭異蓝纲,居然都是意外死亡,警方通過查閱死者的電腦和手機晌纫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門税迷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人锹漱,你說我怎么就攤上這事箭养。” “怎么了哥牍?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵毕泌,是天一觀的道長。 經(jīng)常有香客問我嗅辣,道長撼泛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任辩诞,我火速辦了婚禮坎弯,結果婚禮上,老公的妹妹穿的比我還像新娘译暂。我一直安慰自己抠忘,他們只是感情好,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布外永。 她就那樣靜靜地躺著崎脉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪伯顶。 梳的紋絲不亂的頭發(fā)上囚灼,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天,我揣著相機與錄音祭衩,去河邊找鬼灶体。 笑死,一個胖子當著我的面吹牛掐暮,可吹牛的內容都是我干的蝎抽。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼路克,長吁一口氣:“原來是場噩夢啊……” “哼樟结!你這毒婦竟也來了养交?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤瓢宦,失蹤者是張志新(化名)和其女友劉穎碎连,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體驮履,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡鱼辙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了玫镐。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片座每。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖摘悴,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情舰绘,我是刑警寧澤蹂喻,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站捂寿,受9級特大地震影響口四,放射性物質發(fā)生泄漏。R本人自食惡果不足惜秦陋,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一蔓彩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧驳概,春花似錦赤嚼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至稚照,卻和暖如春蹂空,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背果录。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工上枕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人弱恒。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓署拟,卻偏偏與公主長得像,于是被迫代替她去往敵國和親桐筏。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內容