Flutter Key

什么是key

Key 能夠幫助開發(fā)者在 Widget tree 中保存狀態(tài)钩杰。

Flutter | 深入淺出Key 中使用 key 來解決widget交換的問題?

@immutable
abstract class Widget extends DiagnosticableTree {
  const Widget({ this.key });
  final Key key;
  ···
  static bool canUpdate(Widget oldWidget, Widget newWidget) {
    return oldWidget.runtimeType == newWidget.runtimeType
        && oldWidget.key == newWidget.key;
  }
}

我們知道 Widget 只是一個配置且無法修改,而 Element 才是真正被使用的對象熟掂,并可以修改。

當新的 Widget 到來時將會調用 canUpdate 方法铝宵,來確定這個 Element 是否需要更新打掘。

canUpdate 對兩個(新老) WidgetruntimeTypekey 進行比較华畏,從而判斷出當前的 Element 是否需要更新鹏秋。若 canUpdate 方法返回 true 說明不需要替換 Element尊蚁,直接更新 Widget 就可以了。

StatelessWidget 內部中如何交換 Widget

只比較它們的 runtimeType侣夷。這里 runtimeType 一致横朋,canUpdate 方法返回 true,兩個 Widget 被交換了位置百拓,StatelessElement 調用新持有 Widget 的 build 方法重新構建琴锭,在屏幕上兩個 Widget 便被正確的交換了順序。

  • 交換流程:
  1. Row Widget 為它的子 Widget 提供了一組有序的插槽衙传。對于每一個 Widget决帖,F(xiàn)lutter 都會構建一個對應的 Element。構建的這個 Element Tree 相當簡單蓖捶,僅保存有關每個 Widget 類型的信息以及對子 Widget 的引用地回。你可以將這個 Element Tree 當做就像你的 Flutter App 的骨架。它展示了 App 的結構俊鱼,但其他信息需要通過引用原始 Widget 來查找刻像。
image.png

交換色塊時,Flutter 遍歷Widget 樹并闲。它從Row Widget 開始细睡,然后移動到它的子 WidgetElement 樹檢查 Widget 是否與舊Widget是相同類型和 Key帝火。
canUpdate()它會更新對新 widget的引用溜徙。這里,Widget 沒有設置Key犀填,所以Flutter只是檢查類型萌京。它對第二個孩子做同樣的事情。所以 Element 樹將根據(jù) Widget 樹進行對應的更新宏浩。

image.png

StatefulWidget 中如何交換

color 的定義放在了State中知残,Widget 并不保存State,真正 hold State 的引用的是 Stateful Element比庄。

image.png

(1) 交換控件的次序求妹,Flutter 將遍歷 Element 樹,檢查 Widget 樹中 Row 控件并且更新Element樹中的引用佳窑,然后第一個 Tile 控件檢查它是相同類型制恍,說明不需要更新 ElementElement 會根據(jù)當前 State 展示內容神凑。所以顏色沒有發(fā)生交換

image.png

StatefullWidget 結合 Key

添加 Key 之后的結構

image.png

(1) 當現(xiàn)在執(zhí)行 swap 時, Element 數(shù)中 StatafulWidget 控件除了比較類型外净神,還會比較 key 是否相等:

image.png

只有類型和 key 都匹配時何吝,才算找到對應的 Widget。于是在 Widget Tree 發(fā)生交換后鹃唯,Element Tree 中子控件和原始控件對應關系就被打亂了爱榕,所以Flutter會重建 Element Tree,直到控件們正確對應上坡慌。

image.png

Element 位置被正確更新了

image.png

Where: 在哪設置 Key

如果把 Key 設置到內部會發(fā)生什么

@override
void initState() {
  super.initState();
  tiles = [
    Padding(
      padding: const EdgeInsets.all(8.0),
      child: StatefulColorfulTile(key: UniqueKey()),
    ),
    Padding(
      padding: const EdgeInsets.all(8.0),
      child: StatefulColorfulTile(key: UniqueKey()),
    ),
  ];
}

當點擊按鈕發(fā)生交換之后黔酥,可以看到兩個色塊的顏色會隨機改變,但是我的預期是兩個固定的顏色彼此交換洪橘。

為什么

當Widget 樹中兩個 Padding 發(fā)生了交換跪者,它們包裹的色塊也就發(fā)生了交換:


image.png

然后 Flutter 將進行檢查,以便對 Element 樹進行對應的更新: Flutter 的 Elemetn to Widget 匹配算法將一次只檢查樹的一個層級:

image.png

在第一級熄求,Padding Widget 都正確匹配渣玲。


image.png

在第二級,Flutter 注意到 Tile 控件的Key` 不匹配弟晚,就停用該 Tile Element忘衍,刪除 Widget 和 Element 之間的連接

image.png

解決問題的方法,將 Key 添加到 Padding

總結

  1. canUpdate() 方法根據(jù)(新老) WidgetruntimeTypekey 來更新 Widget && Element指巡。
  2. LocalKey 的意思是: 當 WidgetElement 匹配時淑履,Flutter 只在樹中特定級別內查找匹配的 Key。因此 Flutter 無法在同級中找到具有該 KeyTile Widget藻雪,所以它會創(chuàng)建一個新 Element 并初始化一個新 State秘噪。 就是這個原因,造成色塊顏色發(fā)生隨機改變勉耀,每次交換相當于生成了兩個新的 Widget指煎。

理解 Flutter 中的 Key

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市便斥,隨后出現(xiàn)的幾起案子至壤,更是在濱河造成了極大的恐慌,老刑警劉巖枢纠,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件像街,死亡現(xiàn)場離奇詭異,居然都是意外死亡晋渺,警方通過查閱死者的電腦和手機镰绎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來木西,“玉大人畴栖,你說我怎么就攤上這事“饲В” “怎么了吗讶?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵燎猛,是天一觀的道長。 經常有香客問我照皆,道長重绷,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任纵寝,我火速辦了婚禮论寨,結果婚禮上星立,老公的妹妹穿的比我還像新娘爽茴。我一直安慰自己,他們只是感情好绰垂,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布室奏。 她就那樣靜靜地躺著,像睡著了一般劲装。 火紅的嫁衣襯著肌膚如雪胧沫。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天占业,我揣著相機與錄音绒怨,去河邊找鬼。 笑死谦疾,一個胖子當著我的面吹牛南蹂,可吹牛的內容都是我干的。 我是一名探鬼主播念恍,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼六剥,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了峰伙?” 一聲冷哼從身側響起疗疟,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎瞳氓,沒想到半個月后策彤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡匣摘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年店诗,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片恋沃。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡必搞,死狀恐怖,靈堂內的尸體忽然破棺而出囊咏,到底是詐尸還是另有隱情恕洲,我是刑警寧澤塔橡,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站霜第,受9級特大地震影響葛家,放射性物質發(fā)生泄漏。R本人自食惡果不足惜泌类,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一癞谒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧刃榨,春花似錦弹砚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至苞轿,卻和暖如春茅诱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背搬卒。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工瑟俭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人契邀。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓摆寄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蹂安。 傳聞我的和親對象是個殘疾皇子椭迎,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355