Подробный обзор класса BuildContext

Вы знаете, что это за объект контекста? Вы знаете, что я имею в виду, объект BuildContext с именем context, который все время передается в функцию build (). Это также необходимый параметр для множества статических функций:

build(BuildContext context)
Theme.of(context)
Scaffold.of(context)
MediaQuery.of(context)
Navigator.of(context)

Это помогает вам подниматься вверх и / или через «дерево рендеринга» (или дерево виджетов). В этой статье мы рассмотрим это подробнее. Это означает, что мы собираемся заглянуть «под капот» фреймворка Flutter и перейти к тому, что именно составляет этот объект BuildContext с именем context. Это означает, что мы проходим код. На самом деле, давайте не будем держать вас в напряжении, я вам прямо сейчас расскажу, что это за объект.

Это элемент.

Мне нравятся скриншоты. Нажмите «Заголовок» для Gists.

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

Давай начнем.

Не в контексте

Так получилось, что мы не собираемся подробно рассматривать сам класс BuildContext как таковой. Поскольку он, казалось бы, является таким ключевым игроком во фреймворке Flutter, простого представления той роли, которую он играет в типичном приложении, должно быть достаточно. Кроме того, это абстрактный класс - вам нужно создать подкласс и реализовать все поля и функции, которые он содержит.

Я представлю ниже снимок экрана класса со всей его документацией и удаленными устаревшими функциями - просто чтобы дать вам представление о его роли во Flutter. Вы можете узнать некоторые функции в contains и даже быть удивлены тем, что именно в этом классе находятся эти функции. Затем мы определим точный подкласс, который использует BuildContext. Конечно, я уже рассказал об этом, но все равно оставайся удивленным, хорошо?

Элемент виджетов

Давайте немного отступим и сначала посмотрим на класс StatelessWidget. Ниже приведен снимок экрана со всей исключенной документацией, чтобы вы могли увидеть, из чего состоит StatelessWidget. Ничего особенного, не так ли? Это абстрактный класс, поэтому подкласс, конечно, должен реализовывать свою функцию build (). Мы уже в значительной степени это знали. Однако что это за функция createElement ()? Он создает другой класс, называемый StatelessElement, и фактически передает ссылку на себя в качестве параметра. Давайте теперь посмотрим на этот урок.

Что касается класса StatelessElement, я решил оставить документацию - то немногое, что есть. Также довольно короткий класс. Обратите внимание: он принимает параметр StatelessWidget и передает его своему собственному родительскому классу ComponentElement, и поэтому мы нажимаем на него.

Класс ComponentElement становится более интересным, поэтому я только что сделал снимок экрана с началом этого класса. Обратите внимание, это тоже абстрактный класс. Это тоже имеет смысл, поскольку он содержит ту самую функцию build (), которую необходимо реализовать. Конечно, в настоящий момент мы возвращаемся назад через иерархию классов. Не волнуйтесь, мы снова посетим эти «промежуточные» классы. Теперь у нас есть класс Element, на который мы будем смотреть дальше.

Опять же, мы рассматриваем только начало класса, Element, следующее. Тоже хорошая вещь. По сравнению с предыдущими классами, этот огромный. Всего он состоит из 90 функций и свойств. Да, это действительно важный «элемент». Однако мы пришли к тому, что я имел в виду. Что ты видишь?

Класс Element реализует класс BuildContext. В отличие от Java, например, любой класс в языке программирования Dart может использоваться как интерфейс - вы просто добавляете его имя в конце объявления класса после ключевого слова реализует. Конечно, если ваш класс не является абстрактным, вы должны реализовать все функции и поля, составляющие этот класс. В случае с классом Element, реализующим класс BuildContext с его многочисленными членами - неудивительно, что теперь существует большое количество функций и полей. Завершив это небольшое упражнение, мы можем заключить, что, как и во всех объектно-ориентированных языках, объект типа Element также может быть передан функциям или конструкторам как объект типа BuildContext. Сюрприз !!

В документации Flutter говорится, что они решили использовать BuildContext в качестве интерфейса, чтобы препятствовать прямому манипулированию объектами Element - что бы это ни значило. В любом случае, кто вообще хочет иметь дело с недвижимостью класса 90 !?

Итак, теперь вы знаете, что когда вы размещаете точку останова в своей любимой среде IDE прямо в строке функции build (), вы обнаружите, что параметр контекста, переданный этой функции, в случае StatelessWidget , тот самый объект StatelessElement, который мы впервые увидели, созданный еще на скриншоте StatelessWidget. Обратите внимание, то же самое верно и для StatefuleWidget. Однако в этом случае он включает объект StatefulElement. Оба этих двух типа виджетов перечислены ниже.

Помните, что у каждого виджета есть собственный объект Element (объект BuildContext). Элемент (BuildContext) может принадлежать только одному виджету. Опять же, когда вы впервые изучали Flutter, вы, возможно, пришли к выводу, что все виджеты, составляющие ваше приложение, связаны неким «древовидным» способом. Они есть, но не напрямую. Фактически, это соответствующие им объекты Element, которые связаны вместе. Каждый элемент (контекст) содержит ссылку на свой «родительский» элемент, поскольку именно родительский элемент (контекст) фактически создает «дочерний» элемент при запуске приложения Flutter. Можно сказать, что приложение Flutter состоит из объектов BuildContexts, объединенных в цепочку, составляющих «дерево объектов BuildContext». Они остаются постоянными в течение жизненного цикла приложения, в то время как их «виджеты» могут быть удалены и воссозданы снова и снова. .

Поместите это в контекст

Я воспользуюсь простым примером приложения из предыдущей статьи, чтобы продемонстрировать процесс надувания, задействованный при запуске такого приложения, и то, как каждый виджет включает в себя свой аналог элемента (контекста). Главный экран приложения с его кодом показан ниже. На первый взгляд, у нас есть десять виджетов.

На снимках экрана ниже показано, когда на самом деле вызывается функция createElement для StatelessWidget. Как бы то ни было, соответствующий объект элемента виджета создается в функции его родительского элемента, inflateWidget (). На среднем снимке экрана показана эта функция и показан вновь созданный объект элемента, который затем вызывает свою собственную функцию mount (). Здесь родительский элемент назначается полю экземпляра дочернего элемента, _parent, и далее добавляется к дереву визуализации. Каждому виджету соответствует свой элемент / объект контекста.

Обойтись контекстом

С помощью этой ссылки объектов «BuildContext» у вас есть средства для возврата к «дереву», чтобы получить ранее созданные экземпляры виджетов и объектов состояния. Все эти функции «из», например, перечисленные в начале этой статьи, содержат функцию, реализованную в классе Element и определенную из класса BuildContext:

context.dependOnInheritedWidgetOfExactType<_InheritedTheme>();
context.findAncestorStateOfType<ScaffoldState>();
context.dependOnInheritedWidgetOfExactType<MediaQuery>();
context.dependOnInheritedWidgetOfExactType<_LocalizationsScope>();
context.findRootAncestorStateOfType<NavigatorState>();

Беговая тема

Давайте закончим это парой наиболее популярных реализаций. Работая с Flutter, вы обнаружите, что статическая функция Theme. of () многократно используется во всем фреймворке Flutter. На снимке экрана слева внизу показано обычное приложение - получение объекта ThemeData для предоставления определенного стиля текстовому виджету. Снимок экрана с правой стороны показывает, что функция independentInheritWidgetOfExactType, определенная в классе BuildContext, используется для поиска определенного «типа InheritedWidget» в объекте Map с именем _inheritedWidgets .

Найдите эшафот

Статическая функция Scaffold. of () также очень распространена в приложениях Flutter. Он содержит другую функцию, определенную в классе BuildContext и реализованную в классе Element. Он возвращается через связанный список объектов Element, чтобы найти ранее определенный объект State. Буквально цикл while включает возврат по связному списку объектов Element (каждый имеет ссылку на своего родителя) в поисках виджета указанного типа. В этом случае ищется Scaffold, определенный ранее в дереве визуализации, и возвращается связанный с ним объект State, ScaffoldState.

Давай оставим это здесь. Класс Element реализует класс BuildContext, и когда у меня будет время, мы обратимся к множеству других функций, также реализованных для извлечения многих «элементов» вашего приложения, уже созданных и упоминаемых как часть дерева отрисовки.

Ваше здоровье.

→ Другие рассказы Грега Перри

* Канал Flutter Stable от 10 сентября 2020 г.