无状态窗口小部件类中的键是什么?


78

在flutter文档中,有一个无状态小部件子类的示例代码,如下所示:

class GreenFrog extends StatelessWidget {
  const GreenFrog({ Key key }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return new Container(color: const Color(0xFF2DBD3A));
  }
}

还有这个

class Frog extends StatelessWidget {
  const Frog({
    Key key,
    this.color: const Color(0xFF2DBD3A),
    this.child,
  }) : super(key: key);

  final Color color;

  final Widget child;

  @override
  Widget build(BuildContext context) {
    return new Container(color: color, child: child);
  }
}

什么是密钥?何时应使用此超级构造函数?似乎如果您有自己的构造函数,则必须具有{Key key}为什么?我看到了其他使用super关键字的示例,因此这是我的困惑所在。


在某些方面,该概念类似于React中的关键stackoverflow.com/questions/28329382/…–
onmyway133

1
这家伙可以使用键来提高性能....值得看一看 medium.com/flutter-community/...
stuckedoverflow

Answers:


108

TLDR:所有小部件都应具有一个Key keyas可选参数或其构造函数。 Key是flutter引擎在识别列表中的哪个小部件已更改的步骤中使用的东西。


当您具有可能会被删除/插入的相同类型的小部件列表ColumnRow无论如何)时,此功能很有用。

假设您有此代码(代码不起作用,但您知道了):

AnimatedList(
  children: [
    Card(child: Text("foo")),
    Card(child: Text("bar")),
    Card(child: Text("42")),
  ]
)

潜在地,您可以通过滑动分别删除所有这些小部件。

事实是,当删除一个孩子时,我们的列表中有一个动画。因此,让我们删除“酒吧”。

AnimatedList(
  children: [
    Card(child: Text("foo")),
    Card(child: Text("42")),
  ]
)

问题:如果没有Key,则flutter将无法知道您的第二个元素是否Row消失了。或者,如果它是最后一个消失了,而第二个则改变了孩子。

因此Key,如果没有,您可能会遇到一个错误,即您的请假动画将在最后一个元素上播放!


这就是Key发生的地方。

如果我们再次开始我们的示例,使用键,我们将有:

AnimatedList(
  children: [
    Card(key: ObjectKey("foo"), child: Text("foo")),
    Card(key: ObjectKey("bar"), child: Text("bar")),
    Card(key: ObjectKey("42"), child: Text("42")),
  ]
)

注意键不是子索引而是元素唯一的键。

从这一点来说,如果我们再次删除“ bar”,我们将拥有

AnimatedList(
  children: [
    Card(key: ObjectKey("foo"), child: Text("foo")),
    Card(key: ObjectKey("42"), child: Text("42")),
  ]
)

由于key存在,Flutter引擎现在可以确定删除了哪个小部件。现在,我们的请假动画将在“ bar”(而不是“ 42”)上正确播放。


1
我开始理解您在说什么,我也是移动开发的新手,所以对我来说也很裸露。只是为了从您的解释中澄清一下,即使他们的孩子的文字不同,现在也可以将卡片元素区分开来?因此,要解决此问题,将密钥用作每个元素的唯一ID。它是否正确?
DanT29 '18

1
究竟。为了区分小部件,默认情况下,杂乱使用列表中它们的类型和索引,除非您指定键。
罗米·罗素(RémiRousselet)

1
更有道理,我在原始帖子中还有一个问题已更新为问题2。似乎更多的dartlang您可以尝试解释一下吗?
DanT29 '18

5
颤振是否添加默认键?
伊桑·费尔南多

10
@IshanFernando没有 但是,当没有键时,请使用控件类型及其在数组中的位置作为参考。
雷米Rousselet

7

什么是钥匙?

键是小部件的ID。所有小部件都具有它们,而不仅仅是StatelessWidgets。元素树使用它们来确定小部件是否可以重用或是否需要重建。如果未指定键(通常情况),则使用小部件类型来确定。

为什么要使用钥匙?

当小部件的数量或位置更改时,键对于保持状态很有用。如果没有密钥,则Flutter框架可能会混淆哪个控件已更改。

何时使用按键?

仅在框架需要您的帮助来知道要更新哪个窗口小部件时才使用它们。

大多数时候,您不需要使用键。由于键主要仅用于维护状态,因此,如果您有一个无状态的小部件,其子级都为无状态,则无需在其上使用键。在这种情况下使用键不会有什么坏处,但也无济于事。

您可以使用密钥进行一些微优化。看到这篇文章

在哪里使用钥匙?

将密钥放在小部件树中要进行重新排序或添加/删除的部分。例如,如果要重新排序其子项为ListTile小部件的ListView的项目,则将键添加到ListTile小部件。

使用什么样的钥匙?

密钥只是一个ID,但是您可以更改ID的种类。

值键

ValueKey是一个采用简单值(例如字符串或整数)的本地键。

对象键

如果窗口小部件显示的数据比单个值复杂,则可以为该窗口小部件使用ObjectKey。

唯一键

保证这种类型的密钥每次都会为您提供唯一的ID。但是,如果使用它,请将其放入build方法中。否则,您的小部件将永远不会具有相同的ID,因此元素树将永远不会找到要重用的匹配项。

全局密钥

GlobalKeys可用于维护整个应用程序的状态,但请谨慎使用,因为它们类似于全局变量。通常更可取的是使用状态管理解决方案。

使用按键的例子

参考文献



2

密钥是用于唯一标识窗口小部件的对象。

它们用于访问或还原状态StatefulWidget(大多数情况下,如果我们的窗口小部件树都是无状态窗口小部件,则根本不需要它们)。我将根据用途尝试解释各种密钥。

目的(key types

1.对i.e. remove / add / reorder item to list有状态小部件(例如可拖动的待办事项列表)中的集合进行突变,其中已删除选中的项目

➡️ ObjectKey, ValueKey & UniqueKey

2.将小部件从一个父级移动到另一个父级,以保留其状态。

➡️ GlobalKey

3.在多个屏幕中显示相同的窗口小部件并保持其状态。

➡️ GlobalKey

4.确认表格。

➡️ GlobalKey

5.您想提供一个不使用任何数据的密钥。

➡️ UniqueKey

6.是否可以将某些数据字段(如用户的UUID)用作唯一密钥。

➡️ ValueKey

7.如果您没有用作键的唯一字段,但是对象本身是唯一的。

➡️ ObjectKey

8.如果您有多个需要GlobalKey的表单或相同类型的多个小部件。

➡️ GlobalObjectKey, LabeledGlobalKey whichever is appropriate, similar logic to ValueKey and ObjectKey

❌请勿将随机string/number密钥用作密钥,否则会破坏密钥的用途

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.