當Widget
在Widget Tree
中移動時,Key
會保留其狀態。它們可用於保留用戶的滾動位置等信息。less
Key
主要分爲Local Keys
和Global Keys
;ide
大多數狀況下,咱們並不須要使用Key
。可是若是你發現本身須要添加、刪除或者從新排序處於某種狀態的相同類型的Widget
集合就會用到Key
。ui
import 'package:flutter/material.dart';
class KeyDemoApp extends StatelessWidget{
@override
Widget build(BuildContext context) => MaterialApp(
home: _HomePage(),
);
}
class _HomePage extends StatefulWidget{
@override
State<StatefulWidget> createState() =>_HomePageState();
}
class _HomePageState extends State<_HomePage>{
List<Widget> _widgets;
@override
void initState() {
super.initState();
_widgets= [
RectStateless(Color.fromARGB(255, 0, 0, 0)),
RectStateless(Color.fromARGB(255, 255, 0, 0))
];
}
@override
Widget build(BuildContext context) => Scaffold(
body: Center(
child: Row(children: _widgets,),
),
floatingActionButton: FloatingActionButton(onPressed: swapWidget),
);
void swapWidget(){
setState(() {
_widgets.insert(1, _widgets.removeAt(0));
});
}
}
class RectStateless extends StatelessWidget{
final Color _bg;
RectStateless(this._bg,[Key key]):super(key:key);
@override
Widget build(BuildContext context) {
return Container(color:_bg,
width: 100,
height: 100,
);
}
}
複製代碼
在上面的代碼中,若是點擊按鈕則兩個Widget
能夠自由的更換位置。若是將兩個Widget
更換爲StatefulWidget
的Widget
後:this
class RectStateful extends StatefulWidget{
final Color _bg;
RectStateful(this._bg,[Key key]):super(key:key);
@override
State<StatefulWidget> createState() =>RectStatefulState(_bg);
}
class RectStatefulState extends State<RectStateful>{
final Color _bg;
RectStatefulState(this._bg);
@override
Widget build(BuildContext context) {
return Container(color:_bg,
width: 100,
height: 100,
);
}
}
複製代碼
當點擊時兩個色塊都不會交換,當添加上Key後則又能夠交換位置:spa
_widgets= [
RectStateful(Color.fromARGB(255, 0, 0, 0),UniqueKey()),
RectStateful(Color.fromARGB(255, 255, 0, 0),UniqueKey())
];
複製代碼
從上面的例子能夠看出: 若是集合中的整個小部件子樹是無狀態的,則不須要使用Key。code
在Stateless
的例子中,Row
爲子Widget提供了一組有序的插槽。對於每一個小部件,Flutter都會構建一個相應的Element
,Element tree
只會保存每一個Widget類型以及對子Element的引用信息。能夠將Element tree
視爲Flutter應用程序的骨架,它顯示了應用程序的結構。當交換Row
中的Widget時,Flutter會遍歷Element tree
來查看骨架結構是否相同,即檢查新的Widget是否和舊的Widget的類型和Key是否相同,若是是同樣的,它會更新對新Widget的引用,對於其餘Widget也是對應的步驟。 在Stateless
的例子中,Widget
沒有Key
,Flutter只會檢查其類型。對象
在Stateful
沒有Key
例子中,每一個Widget都會有一個State對象來保存相應的信息,這些信息而不是存儲在小部件自己中。Flutter會檢查Row
小部件的類型,類型是同樣的會更新引用,第二個Widget也如此。Flutter會遍歷Element tree
以及其對應的State
來肯定在設備上顯示的實際內容。所以,看起來相應的Widget並無正確的交換。排序
在有Key
的Stateful
例子中,向小部件添加來key
的屬性。在交換Row
小部件時會像以前同樣匹配。可是新的Widget的密鑰和以前小部件Element
對應的Key不匹配。所以,Flutter會停用這些Element
,從第一個不匹配的Element
開始,而後Flutter會查看不匹配的子項,查找具備相同密鑰的Element,它會找到匹配項,並更新對相應Widget
的引用。而後Flutter會爲後續的子項作相同的事情。rem