Flutter 詳解 Key

轉載 原文鏈接:https://juejin.im/post/6863300824660082701

作者: fgyong

github:https://github.com/ifgyong

Key 是什么

用官方的說法就是:

key是用來作為WidgetElementSemanticsNode的標示,僅僅用來更新widget->key相同的小部件的狀態。

Key子類包含LocalKeyGlobalKey

LocalKey

看下LocalKey的定義:

abstract class LocalKey extends Key {
  const LocalKey() : super.empty();
}

LocalKey定義了初始化函數,默認為值空。

LocalKey子類包含ValueKey/ObjectKey/UniqueKey,如圖所示:

image

ValueKey

ValueKey顧名思義是比較的是值

看下關鍵函數

  @override
  bool operator ==(Object other) {
    if (other.runtimeType != runtimeType)
      return false;
    return other is ValueKey<T>
        && other.value == value;
  }

那么使用起來也是很簡單的,當我們想要系統根據我們所給的key來判斷是否可以刷新時,可以使用該key

TextField(
          key: ValueKey('value1'),
        ),
        TextField(
          key: ValueKey('value2'),
        ),
image

當我們來交換順序時,TextField的值也交換了,也就是我們的key帶走了值。

TextField(
  key: ValueKey('value2'),
),
TextField(
  key: ValueKey('value1'),
),
image

如果我們使用其他類來傳值呢?我們把類Student作為value傳值進去。


class Student {
  final String name;

  Student(this.name);

  @override
  int get hashCode => name.hashCode;
}

TextField(
  key: ObjectKey(Student('老王')),
),
TextField(
  key: ObjectKey(Student('老王')),
),

刷新之后并無報錯,使用正常。

當我們在Student重寫了操作符==之后再看下,我們將Student代碼稍微改動下

class Student {
  final String name;

  Student(this.name);

  @override
  int get hashCode => name.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Student &&
          runtimeType == other.runtimeType &&
          name == other.name;
}

然后hot reload,結果報錯了

If multiple keyed nodes exist as children of another node, they must have unique keys.

剛才我們所改的Student操作符==導致了,在Key對比Value的時候重載了Student的操作符,才導致的報錯,我們需要設置不同姓名的同學,來區分不同的同學。

ObjectKey

顧名思義是比較對象的key,那么這個key是如何比較對象呢?我們看下源碼;

  @override
  bool operator ==(Object other) {
    if (other.runtimeType != runtimeType)
      return false;
    return other is ObjectKey
        && identical(other.value, value);
  }

官方顯示比較類型,當類型不一致,判定為不是通過一個對象,如果另外一個也是ObjectKey,則判斷地址是否相同,只有地址相同才判定為同一個對象。

測試數據;

class Student {
  final String name;

  Student(this.name);

  @override
  int get hashCode => name.hashCode;

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Student &&
          runtimeType == other.runtimeType &&
          name == other.name;
}


TextField(
    key: ObjectKey(Student('老王')),
  ),
  TextField(
    key: ObjectKey(Student('老王')),
  ),

刷新界面之后,并無報錯。

ObjectKey稍微修改

   _student = Student('老王');

  TextField(
    key: ObjectKey(_student),
  ),
  TextField(
    key: ObjectKey(_student),
  ),

刷新之后報錯了,存在了相同的key

If multiple keyed nodes exist as children of another node, they must have unique keys.

UniqueKey

每次生成不同的值,當我們每次刷新都需要一個新的值,那么正是這個存在的意義。

我們每次刷新就生成一個新的 顏色,并且漸隱漸顯效果。

AnimatedSwitcher(
  duration: Duration(milliseconds: 1000),
  child: Container(
    key: UniqueKey(),
    height: 100,
    width: 100,
    color: Colors.primaries[count % Colors.primaries.length],
  ),
)

效果:

image

GlobalKey & GlobalObjectKey

作為全局使用的key,當跨小部件我們通常可以使用GlobalKey來刷新其他小部件。

GlobalObjectKeyObjectKey是否相等的判定條件是一致的,GlobalObjectKey繼承GlobalKey,通過GlobalKey<T extends State<StatefulWidget>>來指定繼承state,并實現StatefulWidget接口的類,然后可以通過GlobalKey.currentState來獲取當前state,然后調用state.setState((){})完成當前小部件標記為dirty,在下一幀刷新當前小部件

例子

點擊按鈕刷新小部件的背景顏色。

GlobalKey _key = GlobalKey();
_Container(_key),
OutlineButton(
  child: Text('global key 刷新'),
  onPressed: () {
    _key.currentState.setState(() {});
  },

點擊globalKey刷新局部小部件,點擊右下角刷新整個頁面。可以看到局部刷新時,只有下邊的小部件改變顏色,整個頁面刷新時。

效果:

image

參考

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,746評論 2 370