Как мне лучше всего получить доступ к BuildContext вложенного виджета из дочернего виджета?

У меня есть StatefulWidget вверху (назовем его верхним виджетом), функция сборки которого выглядит примерно так:

@override
Widget build(BuildContext context) {
return new MaterialApp(
    color: // some color,
    theme: // some theme,
    home: new Scaffold(
        backgroundColor: // some color,
        body: new Builder(builder: (context) {
          _builderContext = context;
          return new Column(
            children: <Widget>[
              new Expanded(
                child: new MaterialApp(
                  color: // some color,
                  theme: // some theme,
                  title: 'title',
                  onGenerateRoute: _onRoute,
                  navigatorKey: _navigatorState,
                  navigatorObservers: observers,
                ),
              ),
              ... etc

Теперь где-нибудь в дочерних виджетах, сгенерированных _onRoute, я хочу вывести нижний лист с showModalBottomSheet(context, ...). Однако контекст, передаваемый в showModalBottomSheet, должен быть контекстом из Builder в методе сборки выше. Если я использую контекст, доступный для ребенка, лист выскакивает не на том нижнем якоре моего пользовательского интерфейса. Теперь ребенок уже может общаться с верхним виджетом с помощью GlobalKey. Однако в другом методе верхнего виджета я могу получить доступ только к его общему контексту. Передача этого контекста в showModalBottomSheet генерирует нулевой указатель.

После долгих исследований и проб и ошибок единственное решение, которое я придумал, - это кэшировать контекст в методе сборки (_builderContext = context;), а затем использовать этот кешированный контекст для передачи его в showModalBottomSheet в другом моем методе верхнего виджета:

openBottomSheet() {
  if (_builderContext != null) {
    showModalBottomSheet(
        context: _builderContext,
        builder: (context) {
          return // some bottom sheet content;
        });
  }
}

На данный момент это, кажется, работает довольно хорошо, но мне было интересно, есть ли более чистый способ сделать это?

Вопрос можно обобщить на то, как я могу получить доступ к контексту в дочерних виджетах в целом. Я попытался придумать решение InheritedWidget, но не мог понять, как я могу каким-то образом сделать Builder унаследованным виджетом, а затем использовать это для моей проблемы.

Любые идеи очень ценятся.


person Ingmar_D.    schedule 17.07.2018    source источник
comment
у вас должен быть один и только один MaterialApp экземпляр   -  person Rémi Rousselet    schedule 17.07.2018
comment
У меня возникла аналогичная проблема с модальными окнами и InheritedWidget - решение заключалось в использовании InheritedWidget в корне моего приложения (т.е. / из main.dart)   -  person surtyaar    schedule 22.04.2020


Ответы (1)


Если бы этот вопрос касался только использования ModalBottomSheet, я бы настоятельно рекомендовал вам использовать плагин Flushbar здесь для Флаттер.

Он довольно гибкий, и вы можете в значительной степени настроить его. Вам не нужно сразу заботиться о контексте и других вещах - редактируйте его так, как вам нужно, и вы также можете использовать его где угодно ... даже если у вас нет предка каркаса. (При использовании нижнего модального листа или каркаса требуется предок каркаса).

Если бы этот вопрос касался только использования контекста в дочернем виджете из родительского виджета, я бы посоветовал вам просто передать его любому class/widget(stateful/stateless) в качестве параметра. Это делает все довольно простым в использовании.

person Aman Malhotra    schedule 17.07.2018
comment
Спасибо, посмотрю на плагин Flushbar. Что касается другого предложения: это, конечно, загромождает конструкторы виджетов, если мне нужно передать контекст на несколько шагов вниз по иерархии. Кроме того: не мог ли контекст в какой-то момент устареть? Третья проблема заключается в том, что дочерние виджеты не вложены напрямую в метод сборки, а генерируются через onGenerateRoute. Так что я бы все равно вернулся к кешированию контекста снова. - person Ingmar_D.; 18.07.2018