Hola Amigos! На связи Тимур Моисеев, руководитель мобильной разработки Amiga. 

Еще раз кратко пройдемся по теме ключей у виджетов. Хочется осветить пару моментов, которые будут полезны как начинающим разработчикам, так и тем, кто уже немного погрузился во Flutter.

Вы наверняка заметили, что виджеты имеют необязательный параметр key в своем вызове.

class MyWidget extends StatelessWidget {
  const MyWidget({super.key});

  @override
  Widget build(BuildContext context) {
    return const Placeholder();
  }
}

Но для начала давайте немного познакомимся! Я кандидат технических наук, в IT уже более 20 лет, а последние 4 года создаю мобильные приложения на Flutter.

Вместе с командой ведем телеграм-канал Flutter.Много, где делимся личным опытом и кейсами. Переводим интересные статьи иностранных СМИ, рассказываем про конференции, на которых выступаем и с радостью встречаемся вживую с любителями кроссплатформенности. Присоединяйтесь! 

Для чего нужен ключ виджета?

Для начала немного углубимся в то, как Flutter устроен “под капотом”

Если упрощенно о том, как устроен рендеринг во Flutter:

В коде содержится описание виджетов, при вызове метода build строится дерево виджетов, на его основе происходит построение дерева элементов, которое создает дерево рендеринга. В общем, и все :)

Магия начинается в тот момент, когда необходимо сделать так, чтоб это все работало крайней быстро.

Для этой цели элементы создаются очень “легкими”. И если вы меняете местами одинаковые виджеты, например два контейнера с разными цветами, то дерево элементов не перестраивается, т.к. для Flutter не произошло никаких изменений, и вы не увидите никаких изменений на экране.

Чтобы программист мог этим поведением управлять были реализованы ключи виджетов — key.

Суть в том, что ключ — это связь с элементом, которая позволяет управлять рендерингом виджета и не только.

Так почему разработчики Flutter не указали ключи по умолчанию? Все просто, наличие ключей делает обработку “дорогой”. И если нужно отображать 60 кадров в секунду, то требуется оптимизация на каждом шаге, поэтому ключи не указаны по умолчанию.

Какие варианты ключей существуют?

На данный момент во Flutter существует несколько вариантов ключей.

Локальные ключи:

UniqueKey

ValueKey

ObjectKey

PageStorageKey

Глобальный ключ:

GlobalKey

Суть всех ключей сводится к одному простому действию — позволяет вам управлять рендерингом вашего виджета. Иначе говоря, указывая ключ вы можете управлять состоянием виджета, т.е. ключ позволяет сохранять состояние виджета, не сбрасывая его, когда вызывается метод build.

Но это работает только в том случае, если созданный ключ находится выше вызываемого метода build.

В чем же отличие локальных ключей от глобальных ключей?

Локальные ключи сохраняют состояние внутри контекста и не имеют к нему доступ. Предполагалось, что они будут использоваться внутри страницы для управления состоянием виджетов.

Глобальный ключ немного сложнее. Он имеет собственное состояние и позволяет обратиться к состоянию виджета, его положению и прочим свойствам.

Например:

Rect getRectFromKey(GlobalKey key) {
  RenderBox renderBox = (key.currentContext!.findRenderObject())! as RenderBox;
  var targetPosition = renderBox.localToGlobal(Offset.zero);
  var targetSize = renderBox.size;

  Rect rect = targetPosition & targetSize;
  return rect;
}

Этот метод позволяет вернуть положение виджета на экране.

Задача со звёздочкой

Т.к. глобальный ключ имеет собственное состояние, то ему нашли применение в виде построения вложенной навигации на основе глобального ключа.

class GlobalNavigatorKey extends StatelessWidget {
  static final GlobalKey<NavigatorState> globalKey = GlobalKey();

  const GlobalNavigatorKey({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Navigator(key: globalKey);
  }
}

Суть в том, что сохраняя глобальный ключ, мы имеем возможность управлять навигацией без обращения к контексту.

Данное решение было придумано для декларативного навигатора, чтоб дать ему возможность управлять состоянием.

Рекомендую также ознакомиться с моей статьей «Вложенная навигация во Flutter: что такое декларативный роутер и зачем он нужен».

И не забудь подписаться на телеграм-канал Flutter.Много, нас там уже более 1660 человек :)

Комментарии (0)