如何在应用程序中任何地方显示对话框而不需要上下文?

13

大家好,这是我一直在思考的问题。我也看到了一些回答,但它们并没有解决我的问题,我找到的一些类似的问题如下:Flutter showDialog with navigator key rather than passing contextNavigator operation requested with a context that does not include a Navigator

我想要实现的是从同一段代码中在应用的任何地方(因此在应用的任何页面)显示弹出对话框(因此都集中在一起)。问题在于,从那段代码中我没有访问BuildContext的权限,这是因为我基于不来自用户操作(例如按钮点击)的事件显示这些弹出对话框,而是可能是Firestore监听器或深入我的代码中发生的错误(因此我可以向用户显示错误消息),由于我深入了代码,通常我无法访问BuildContext。

在类似的问题中,我找到了一些看起来像解决方案的东西。这些解决方案使用一个全局键值(GlobalKey)来获取导航器,以便可以从应用程序的任何位置访问它,有一些不同的选项可以在应用程序的任何位置访问它,在我的情况下,我选择使用单例(我的“Repository”),在其中存储这个全局键值。然后当事件触发时,我使用全局键值来获取上下文并显示对话框,但它会抛出此错误:

Navigator operation requested with a context that does not include a Navigator.
The context used to push or pop routes from the Navigator must be that of a widget that is a descendant of a Navigator widget.

@Hemanth Raj提到您的根Widget需要是MaterialApp,我的根已经是MaterialApp了。

以下是我所拥有的应用程序结构的近似表示:

void main() async {

  // Here I create the navigatorKey
  GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();

  // I then init my Singleton with the navigatorKey
  await repository.init(navigatorKey: navigatorKey);

  // Then I pass the navigatorKey down to my App
  runApp(MyApp(debugMode: debugMode, navigatorKey: navigatorKey));
}

class MyApp extends StatefulWidget {
  final navigatorKey;

  const MyApp({Key key, this.navigatorKey})
      : super(key: key);

  @override
  MyAppState createState() => MyAppState();
}

class MyAppState extends State<MyApp> with WidgetsBindingObserver {

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        navigatorKey: widget.navigatorKey,
        title: 'My app',
        home: SplashPage(),
        theme: _buildMyTheme(),
      );
  }
}

那么在我的代码库中,我有一个监听器用于Firestore事件。这些事件可以随时在我进入主屏幕后触发。思路是无论我在应用程序的哪个位置,如果事件被触发,则应该弹出弹出窗口。

class Repository {

  GlobalKey<NavigatorState> get navigatorKey => _navigatorKey;
  GlobalKey<NavigatorState> _navigatorKey;

  void init({GlobalKey<NavigatorState> navigatorKey}) {
    _navigatorKey = navigatorKey;
  }

  void _listenToEvents() {
    streamWithEvents.listen((event) {
      showDialog(
        context: navigatorKey.currentContext,
        builder: (_) => CustomMessageDialog(message: event.message),
      );
    });
  }
}

如果您使用MaterialApp.router,请查看https://dev59.com/acLra4cB1Zd3GeqPBxhr - Hadi Albinsaad
1个回答

10

使用 navigatorKey.currentState.overlay.context 替代 showDialog 的 context。


非常感谢您的回答!我会尝试这个方法,并且再与您联系。如果有效,我将把这个答案标记为正确答案。 - Migalv

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接