一、Flutter Tips - Widget Key;

  當WidgetWidget Tree中移動時,Key會保留其狀態。它們可用於保留用戶的滾動位置等信息。less

Key的種類

   Key主要分爲Local KeysGlobal Keys;ide

Local Keys

  • ValueKey : ValueKey('value')
  • ObjectKey : ObjectKey(MutableRectangle(1,2,3,4))
  • UniqueKey : UniqueKey()
  • PageStorageKey : PageStorageKey(scrollLocation)

Global Keys

  • GlobalKey : GlobalKey()

何時使用Key

  大多數狀況下,咱們並不須要使用Key。可是若是你發現本身須要添加、刪除或者從新排序處於某種狀態的相同類型的Widget集合就會用到Keyui

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更換爲StatefulWidgetWidget後: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

Key的運做方式

  在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並無正確的交換。排序

  在有KeyStateful例子中,向小部件添加來key的屬性。在交換Row小部件時會像以前同樣匹配。可是新的Widget的密鑰和以前小部件Element對應的Key不匹配。所以,Flutter會停用這些Element,從第一個不匹配的Element開始,而後Flutter會查看不匹配的子項,查找具備相同密鑰的Element,它會找到匹配項,並更新對相應Widget的引用。而後Flutter會爲後續的子項作相同的事情。rem

相關文章
相關標籤/搜索