Flutter 中的key、LocalKey、GlobalKey等等

key之間的關係

在這裏插入圖片描述

key

@immutable
abstract class Key {
  const factory Key(String value) = ValueKey<String>;

  @protected
  const Key.empty();
}

默認創建 Key 將會通過工廠方法根據傳入的 value 創建一個 ValueKey。
Key 派生出兩種不同用途的 Key:LocalKey 和 GlobalKey。

LocalKey

LocalKey 直接繼承至 Key,它應用於擁有相同父 Element 的小部件進行比較的情況,也就是上述例子中,有一個多子 Widget 中需要對它的子 widget 進行移動處理,這時候你應該使用Localkey。

Localkey 派生出了許多子類 key:

  • ValueKey : ValueKey(‘String’)
  • ObjectKey : ObjectKey(Object)
  • UniqueKey : UniqueKey()
  • Valuekey 又派生出了 PageStorageKey : PageStorageKey(‘value’)

GlobalKey

@optionalTypeArgs
abstract class GlobalKey<T extends State<StatefulWidget>> extends Key {
···
static final Map<GlobalKey, Element> _registry = <GlobalKey, Element>{};
static final Set<Element> _debugIllFatedElements = HashSet<Element>();
static final Map<GlobalKey, Element> _debugReservations = <GlobalKey, Element>{};
···
BuildContext get currentContext ···
Widget get currentWidget ···
T get currentState ···

GlobalKey 使用了一個靜態常量 Map 來保存它對應的 Element。
你可以通過 GlobalKey 找到持有該GlobalKey的 Widget,State 和 Element。
注意:GlobalKey 是非常昂貴的,需要謹慎使用。

什麼時候需要使用 Key

ValueKey

如果您有一個 Todo List 應用程序,它將會記錄你需要完成的事情。我們假設每個 Todo 事情都各不相同,而你想要對每個 Todo 進行滑動刪除操作。

這時候就需要使用 ValueKey!

return TodoItem(
    key: ValueKey(todo.task),
    todo: todo,
    onDismissed: (direction){
        _removeTodo(context, todo);
    },
);

ObjectKey

如果你有一個生日應用,它可以記錄某個人的生日,並用列表顯示出來,同樣的還是需要有一個滑動刪除操作。

我們知道人名可能會重複,這時候你無法保證給 Key 的值每次都會不同。但是,當人名和生日組合起來的 Object 將具有唯一性。

這時候你需要使用 ObjectKey!

UniqueKey

如果組合的 Object 都無法滿足唯一性的時候,你想要確保每一個 Key 都具有唯一性。那麼,你可以使用 UniqueKey。它將會通過該對象生成一個具有唯一性的 hash 碼。

不過這樣做,每次 Widget 被構建時都會去重新生成一個新的 UniqueKey,失去了一致性。也就是說你的小部件還是會改變。

PageStorageKey

當你有一個滑動列表,你通過某一個 Item 跳轉到了一個新的頁面,當你返回之前的列表頁面時,你發現滑動的距離回到了頂部。這時候,給 Sliver 一個 PageStorageKey!它將能夠保持 Sliver 的滾動狀態。

GlobalKey

GlobalKey 能夠跨 Widget 訪問狀態。 在這裏我們有一個 Switcher 小部件,它可以通過 changeState 改變它的狀態。

class SwitcherScreenState extends State<SwitcherScreen> {
  bool isActive = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Switch.adaptive(
            value: isActive,
            onChanged: (bool currentStatus) {
              isActive = currentStatus;
              setState(() {});
            }),
      ),
    );
  }

  changeState() {
    isActive = !isActive;
    setState(() {});
  }
}

但是我們想要在外部改變該狀態,這時候就需要使用 GlobalKey。

class _ScreenState extends State<Screen> {
  final GlobalKey<SwitcherScreenState> key = GlobalKey<SwitcherScreenState>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SwitcherScreen(
        key: key,
      ),
      floatingActionButton: FloatingActionButton(onPressed: () {
        key.currentState.changeState();
      }),
    );
  }
}

這裏我們通過定義了一個 GlobalKey 並傳遞給 SwitcherScreen。然後我們便可以通過這個 key 拿到它所綁定的 SwitcherState 並在外部調用 changeState 改變狀態了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章