Что делает BuildContext в Flutter?

Что делает BuildContext и какую информацию мы получаем из него?

https://docs.flutter.io/flutter/widgets/BuildContext-class.html просто неясен.

https://flutter.io/widgets-intro/#basic-widgets для 9-го экземпляра термина BuildContext есть пример, но не ясно, как он используется. Это часть гораздо большего набора кода, который теряет меня, и поэтому мне трудно понять, что такое BuildContext.

Может кто-нибудь объяснить это простыми/очень простыми словами?

Ответ 1

BuildContext, как это подразумевает название, контекст, в котором построен конкретный виджет.

Если вы когда-либо делали некоторые действия React, этот контекст похож на контекст React (но гораздо более плавный в использовании); с несколькими бонусами.

Вообще говоря, существует 2 случая использования контекста:

  • Взаимодействие с вашими родителями (обычно получайте/публикуйте данные)
  • После отображения на экране получите размер и положение экрана

Вторая точка немного редка. С другой стороны, первая точка используется почти везде.

Например, если вы хотите нажать новый маршрут, вы сделаете Navigator.of(context).pushNamed('myRoute').

Обратите внимание на контекст здесь. Он будет использоваться для получения ближайшего экземпляра виджета NavigatorState выше в дереве. Затем вызовите метод pushNamed в этом экземпляре.


Прохладный, но когда I хотите его использовать?

BuildContext действительно полезен, когда вы хотите передавать данные вниз, не назначая вручную все виджеты. Конфигурации, например; вы захотите получить к ним доступ повсюду. Но вы не хотите передавать его на каждый конструктор.

Вы могли бы создать глобальный или одноэлементный; но тогда, когда confs change, ваши виджеты не будут автоматически восстанавливаться.

В этом случае вы используете InheritedWidget. С его помощью вы могли бы написать следующее:

class Configuration extends InheritedWidget {
  final String myConf;

  const Configuration({this.myConf, Widget child}): super(child: child);

  @override
  bool updateShouldNotify(Configuration oldWidget) {
    return myConf != oldWidget.myConf;
  }
}

И затем используйте его следующим образом:

void main() {
  runApp(
    new Configuration(
      myConf: "Hello world",
      child: new MaterialApp(
        // usual stuff here
      ),
    ),
  );
}

Благодаря этому, теперь везде внутри вашего приложения, вы можете получить доступ к этим конфигам, используя BuildContext. Выполняя

final configuration = context.inheritFromWidgetOfExactType(Configuration);

И даже кулер состоит в том, что все виджеты, которые вызывают inheritFromWidgetOfExactType(Configuration), автоматически перестраиваются при изменении конфигураций.

Удивительное право?

Ответ 2

Класс BuildContext - это не что иное, как ссылка на расположение виджета в древовидной структуре всех созданных виджетов.

Каждый виджет Flutter имеет @override build() с аргументом BuildContext.

class CartItemWidget extends StatelessWidget {

  @override
  Widget build(BuildContext context) {.....

Просто объясните, что BuildContext это:

  1. BuildContext принадлежит только одному виджету.
  2. Объекты BuildContext передаются в функции WidgetBuilder

BuildContext принадлежит только одному виджету.

Если виджет 'A имеет дочерние виджеты, BuildContext виджета' A станет родительским BuildContext для прямых дочерних BuildContexts.

Читая это, становится ясно, что BuildContexts в цепочки и составляют дерево BuildContexts (отношения родитель-дети).

enter image description here

Если мы сейчас попытаемся проиллюстрировать понятие BuildContext на предыдущей диаграмме, мы получим (все еще в очень упрощенном виде), где каждый цвет представляет BuildContext (кроме MyApp, который отличается):

На следующей диаграмме показана (упрощенная версия) последовательность действий/вызовов, связанных с созданием виджета с отслеживанием состояния.

Состояние виджетов не зависит от параметров, и все же оно перестраивалось при каждом изменении параметров. В таком случае нужно использовать InheritedWidget

InheritedWidget - это особый вид виджета, который определяет контекст в корне поддерева. Он может эффективно доставить этот контекст каждому виджету в этом поддереве. Шаблон доступа выглядел бы знакомым для разработчиков Flutter:

class MyInheritedWidget extends InheritedWidget {

MyInheritedWidget({
      Key key,
      @required Widget child,
      this.data,
   }): super(key: key, child: child);

   final data;

   static MyInheritedWidget of(BuildContext context) {
      return context.inheritFromWidgetOfExactType(MyInheritedWidget);
   }

   @override
   bool updateShouldNotify(MyInheritedWidget oldWidget) => data != oldWidget.data;
}

static MyInheritedWidget of(BuildContext context) позволяет всем static MyInheritedWidget of(BuildContext context) виджетам получить экземпляр ближайшего MyInheritedWidget "который заключает контекст

Наконец, переопределенный метод updateShouldNotify используется, чтобы сообщить InheritedWidget, нужно ли передавать уведомления всем updateShouldNotify виджетам (которые зарегистрированы/подписаны), если к данным будет применена модификация.

для дополнительной информации

  1. Контекст построения
  2. Widget, государство, BuildContext, InheritedWidget
  3. Наследование виджетов