Каковы ключи в классе виджетов без учета состояния?

В документации по флаттеру приведен пример кода для подкласса виджетов без состояния, как показано ниже:

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 не используется, так что это мое замешательство.

Ответ 1

TL;DR: все виджеты должны иметь Key key качестве необязательного параметра или их конструктор. Key - это то, что используется движком флаттера на этапе распознавания того, какой виджет в списке изменился.


Это полезно, когда у вас есть список (Column, Row и т.д.) Виджетов того же типа, которые потенциально могут быть удалены/вставлены.

Допустим, у вас есть это (код не работает, но вы поняли):

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 флаттер не сможет узнать, исчез ли второй элемент вашей 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")),
  ]
)

обратите внимание, что ключ - это не дочерний индекс, а нечто уникальное для элемента.

С этого момента, если мы удалим "бар" снова, мы будем иметь

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

Благодаря наличию key движок флаттера теперь точно знает, какой виджет был удален. И теперь наша анимация выхода будет корректно воспроизводиться на "баре" вместо "42".

Ответ 2

Ключ - это необязательный параметр, необходимый для сохранения состояния в вашем дереве виджетов, вы должны использовать его, если хотите переместить коллекцию элементов в вашем дереве и сохранить их состояние.

Лучшее объяснение можно найти в этом видео от Google, когда использовать ключи - Flutter Widgets 101 Ep. 4