如何最好地从子小部件访问嵌套小部件的 BuildContext?

Posted

技术标签:

【中文标题】如何最好地从子小部件访问嵌套小部件的 BuildContext?【英文标题】:How can I best access the BuildContext of a nested widget from a child widget? 【发布时间】:2018-12-25 11:00:29 【问题描述】:

我在顶部有一个 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 的上下文。如果我使用对孩子可用的上下文,则工作表会在我的 UI 的错误底部锚点处弹出。现在,孩子已经可以通过 GlobalKey 与顶部小部件进行通信了。但是,在顶部小部件的另一种方法中,我只能访问其一般上下文。将此上下文传递给 showModalBottomSheet 会引发空指针。

经过大量研究和反复试验,我想出的唯一解决方案是在构建方法中缓存上下文 (_builderContext = context;),然后使用这个缓存的上下文将其传递到我的另一个顶部小部件中的 showModalBottomSheet方法:

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

目前,这似乎工作得很好,但我想知道是否有更清洁的方法来做到这一点?

这个问题可以概括为我一般如何访问子小部件中的上下文。我尝试提出一个 InheritedWidget 解决方案,但无法真正理解如何以某种方式使 Builder 成为继承的小部件,然后将其用于我的问题。

非常感谢任何想法。

【问题讨论】:

你应该只有一个MaterialApp实例 我遇到了关于模式和 InheritedWidget 的类似问题 - 解决方案是在我的应用程序的根目录中使用“InheritedWidget”(即/来自 main.dart) 【参考方案1】:

如果这个问题只是为了使用 ModalBottomSheet,我强烈建议你使用 Flushbar Plugin here 来解决 Flutter。

它非常灵活,您可以在很大程度上对其进行自定义。您不必立即处理上下文和其他内容——根据需要对其进行编辑,您也可以在任何地方使用它……即使您没有脚手架祖先。 (在使用底部模态表或脚手架时,它需要一个脚手架祖先)。

如果这个问题只是关于在父小部件的子小部件中使用上下文,我建议您简单地将其传递给任何class/widget(stateful/stateless) 作为参数。它使一切都非常易于使用。

【讨论】:

谢谢,我会研究一下 Flushbar 插件。至于另一个建议:如果我需要将上下文向下传递几个步骤,这当然会使小部件构造函数变得混乱。除此之外:上下文在某些时候不会变得“陈旧”吗?第三个问题是子widget不是直接嵌套在build方法中,而是通过onGenerateRoute生成的。所以无论如何我都会再次缓存上下文。【参考方案2】:

当您已经拥有GlobalKey 时,您还需要key.currentContext 吗?不过,在调用它之前,请确保您测试它是否为 null,就像您对 _builderContext 所做的那样。

【讨论】:

以上是关于如何最好地从子小部件访问嵌套小部件的 BuildContext?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Qt 中将消息从子窗口小部件发送到父窗口?

Flutter:从子 StreamBuilder 更新有状态小部件

如何将卡片小部件放在 SliverAppBar 中?

从子小部件中删除 QGraphicsEffect [重复]

如何从 Flutter 中的子小部件调用父小部件功能

如何从stackedLayout访问centralWidget中的小部件?