文章來源于Flutter Widgets 101 Ep. 4,感興趣的同學可以直接看視頻塘雳,更便于理解陆盘。
首先,我們要明白Key的作用败明,Keys preserve state when widgets move around in your widget tree. They can be used to preserve the user's scroll location, or keeping state when modifying a collection. (當組件在組件樹中移動時使用Key可以保持組件之前的狀態(tài)隘马,比如在用戶滑動時或者集合改變時),這是一個抽象的定義妻顶,大家盡量理解原文酸员,在后面的例子中可以很好的理解。
什么時候使用Key讳嘱?
我們參照視頻幔嗦,寫下了如下Demo,當點擊FloatingActionButton時,交換兩個Widget的位置沥潭。(你可以下載項目邀泉,運行一下,會更便于理解)
- 當我們使用Stateless Widget時,widget可以正常的移動汇恤。swap_color_1.dart
- 當我們把Widget改為Stateful時庞钢,交換出現(xiàn)了問題。swap_color_2.dart
- 當我們?yōu)镾tateful加入Key之后因谎,程序又能正常的執(zhí)行swap_color_3.dart
從Demo中我們可以看出基括,當使用Stateless Widget時,我們并不需要使用key财岔,當使用Stateful Widget時阱穗,集合內(nèi)有數(shù)據(jù)移動和改變并且需要展示到界面時才需要key。
Key應(yīng)該用到哪使鹅?
首先我們來搞懂上面揪阶,為什么swap_color_2會出問題,要明白這個問題患朱,我們需要明白Flutter的渲染策略鲁僚。
我們在構(gòu)建Flutter的UI時是以Widget的形式『拼接』出來的,組件樹作為UI每一個組件都對應(yīng)一個元素(原文中是Slot)裁厅,從而形成了『元素樹』(Element Tree)冰沙,元素樹的內(nèi)容非常簡單,只包含了組件的類型和子元素的引用(Type)执虹,你可以把元素樹當做Flutter App中的骨架(skeleton),它只展現(xiàn)了App的結(jié)構(gòu)拓挥,并不包含其他具體的信息。
當我們交換組件樹中的元素時袋励,組件確實進行了交換侥啤,但是元素樹卻不一定。Flutter會先遍歷(walk)整個元素樹茬故,從Row上的主元素盖灸,到主元素的子元素,查看整體的結(jié)構(gòu)是否發(fā)生了變化磺芭,當然赁炎,它檢查的只能是元素的Type和Key,在給出的例子中钾腺,當我們不設(shè)置Key時徙垫,元素樹對比Type,發(fā)現(xiàn)Type并沒有發(fā)生變化放棒,而Flutter卻是用元素樹和元素對應(yīng)的狀態(tài)(可用或者不可用)姻报,來決定這個元素是否應(yīng)該顯示出來,所以在界面中并沒有發(fā)生改變哨查,但是當我們加入Key之后逗抑,對比的對象多了一個,并且是和之前不一樣的寒亥,F(xiàn)lutter察覺到之后邮府,立即改變了元素的狀態(tài),讓它變?yōu)椤簾o用狀態(tài)』(deactivate)溉奕,當遍歷完之后褂傀,F(xiàn)lutter會瀏覽(look through)這些不匹配的元素(non-matched children)通過相應(yīng)的引用為之找到對應(yīng)的組件。當所有的元素都匹配完成之后加勤,F(xiàn)lutter會刷新界面仙辟,展現(xiàn)出我們預想的。
那么Key到底應(yīng)該用到哪呢鳄梅?
我們再來一個例子叠国,swap_color_4,我們把色塊用Padding包裝一下戴尸。運行之后會發(fā)現(xiàn)粟焊,色塊并沒有交換,而是以隨機的形式在變換顏色孙蒙。為什么呢项棠?
結(jié)合我們上面的理論,我們分析一下這次的Widget Tree 和 Element Tree挎峦,當我們交換元素后香追,F(xiàn)lutter element-to-widget matching algorithm,(元素-組件匹配算法),開始進行對比坦胶,算法每次只對比一層透典,即Padding這一層。顯然顿苇,Padding并沒有發(fā)生本質(zhì)的變化掷匠。
于是開始進行第二層對比,在對比時Flutter發(fā)現(xiàn)元素與組件的Key并不匹配岖圈,于是讹语,把它設(shè)置成不可用狀態(tài),但是這里所使用的Key只是本地Key(Local Key)蜂科,F(xiàn)lutter并不能找到另一層里面的Key(即另外一個Padding Widget中的Key)所以顽决,F(xiàn)lutter就創(chuàng)建了一個新的Widget,而這個Widget的顏色就成了我們看到的『隨機色』导匣。
通過上面的示例才菠,我們能明顯的看出,我們的Key要設(shè)置到組件樹的 頂層贡定,而這一層在改變時赋访,才能復用或者更新狀態(tài)。
用哪一種Key?
Flutter中有很多Key蚓耽,但是總體分為兩種 Local Key和Global Key兩種渠牲。
對于Key的研究還不是特別多,有時間再補一篇步悠,上面的例子签杈,因為沒有數(shù)據(jù),所以使用了UniqueKey鼎兽,在真實的開發(fā)中答姥,我們可以用Model中的id作為ObjectKey。
GlobalKey其實是對應(yīng)于LocalKey谚咬,上面我們說Padding中的就是LocalKey鹦付,Global即可以在多個頁面或者層級復用,比如兩個頁面也可也同時保持一個狀態(tài)择卦。
還處在學習Flutter狀態(tài)敲长,如有錯誤請您及時指正,謝謝互捌。