代码之家  ›  专栏  ›  技术社区  ›  szotp

从根窗口小部件显示对话框

  •  1
  • szotp  · 技术社区  · 7 年前

    NavigatorState 实例,但showDialog需要返回的上下文 Navigator.of(context) .

    看起来我需要从路由提供上下文,但我不能这样做,因为根小部件没有它。

    编辑:我找到了一个解决方法:我可以推送只有showDialog才有的假路由,然后在对话框结束时弹出该路由。不漂亮但很管用。

    3 回复  |  直到 7 年前
        1
  •  51
  •   szotp    6 年前

    我用电脑解决了这个问题 navigatorKey.currentState.overlay.context

    class GlobalDialogApp extends StatefulWidget {
      @override
      _GlobalDialogAppState createState() => _GlobalDialogAppState();
    }
    
    class _GlobalDialogAppState extends State<GlobalDialogApp> {
      final navigatorKey = GlobalKey<NavigatorState>();
    
      void show() {
        final context = navigatorKey.currentState.overlay.context;
        final dialog = AlertDialog(
          content: Text('Test'),
        );
        showDialog(context: context, builder: (x) => dialog);
      }
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          navigatorKey: navigatorKey,
          home: Scaffold(
            body: Center(
              child: RaisedButton(
                child: Text('Show alert'),
                onPressed: show,
              ),
            ),
          ),
        );
      }
    }
    
        2
  •  7
  •   NiklasPor    7 年前

    tl;博士: showDialog 从根小部件中,将代码挤出到另一个小部件中(例如 StatelessWidget 显示对话框

    无论如何,在下面我将假设您遇到了这个问题:

    flutter: No MaterialLocalizations found. 
    flutter: MyApp widgets require MaterialLocalizations to be provided by a Localizations widget ancestor. 
    flutter: Localizations are used to generate many different messages, labels,and abbreviations which are used by the material library.
    

    showDialog 只能在短时间内调用 BuildContext 谁的祖先有 MaterialApp 不能 直呼 显示对话框

    - MaterialApp
      - Scaffold
        - Button // call show Dialog here
    

    在代码示例中,这将导致这样的代码, 上面给出的错误:

    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          theme: ThemeData(),
          home: Scaffold(
            body: Center(
              child: RaisedButton(
                  child: Text('Show dialog!'),
                  onPressed: () {
                    showDialog(
                        context: context,
                        builder: (BuildContext context) {
                          return Dialog(
                            child: Text('Dialog.'),
                          );
                        });
                  }),
            ),
          ),
        );
      }
    }
    

    Widget ,它有自己的 BuildContext . 修改后的结构如下所示:

    - MaterialApp
      - Home
    
    - Home     // your own (Stateless)Widget
      - Button // call show Dialog here
    

    显示对话框 没有 抛出错误。

    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          theme: ThemeData(),
          home: Home()
        );
      }
    }
    
    class Home extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Center(
            child: RaisedButton(
                child: Text('Show dialog!'),
                onPressed: () {
                  showDialog(
                      context: context,
                      builder: (BuildContext context) {
                        return Dialog(
                          child: Text('Dialog.'),
                        );
                      });
                }),
          ),
        );
      }
    }
    
        3
  •  2
  •   Oliver Dixon    6 年前

    他们改变了导航覆盖的工作方式。 这是我们的有效解决方案,因为已被接受的解决方案已经不复存在。

    // If you want to use the context for anything.
    final context = navigatorKey.currentState.overlay.context;
    // How to insert the dialog into the display queue.
    navigatorKey.currentState.overlay.insert(anyDialog);
    
        4
  •  1
  •   vipin agrahari    7 年前

    自从 showDialog MaterialApp 仅小部件。它不能用于在其外部显示对话框。

        5
  •  0
  •   Dustin Silk    6 年前

    如果它对其他任何人都有帮助,那么将navigator键注入一个对话框小部件,如下所示。

    class MyApp extends StatelessWidget {
      MyApp({Key key});
    
      final navigatorKey = GlobalKey<NavigatorState>();
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          navigatorKey: navigatorKey,
          onGenerateRoute: Router.generateRoute,
          // ...
          builder: (context, routeChild) {
            return Material(
              child: InviteRequestModal(
                navigatorKey: navigatorKey,
                child: routeChild,
              ),
            );
          },
        );
      }
    

    然后在需要模态的小部件中,您可以如上所述使用它。

    class InviteRequestModal extends StatelessWidget {
      final Widget child;
      final GlobalKey<NavigatorState> navigatorKey;
    
      InviteRequestModal({
        Key key,
        this.child,
        this.navigatorKey,
      }) : super(key: key);
    
      void _showInviteRequest(InviteRequest invite) {
        final context = navigatorKey.currentState.overlay.context;
    
        showDialog(
          context: context,
          builder: (_) {
            // Your dialog content
            return Container();
          }
        );
      }
    
      @override
      Widget build(BuildContext context) {
        return BlocListener<InviteContactsBloc, InviteContactsState>(
          listenWhen: (previous, current) => current is InviteRequestLoaded,
          listener: (_, state) {
            if (state is InviteRequestLoaded) {
              _showInviteRequest(state.invite);
            }
          },
          child: child,
        );
      }
    }
    
        6
  •  0
  •   Moosch    5 年前

    对于那些希望了解如何在多窗口小部件/路由/文件场景中实现这一点的人,我将其与 InheritedWidget 以及 BuildContext .

    main.dart

    import 'package:flutter/material.dart';
    import 'package:myapp/home_screen.dart';
    import 'package:myapp/app_navkey.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      final navigatorKey = GlobalKey<NavigatorState>();
      @override
      Widget build(BuildContext context) {
        return AppNavKey(
          navigatorKey: navigatorKey,
          child: MaterialApp(
            navigatorKey: navigatorKey,
            theme: ThemeData(),
            home: Scaffold(
              body: HomeScreen(),
            ),
          ),
        );
      }
    }
    

    home_screen.dart

    import 'package:myapp/extensions.dart';
    
    class HomeScreen extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        final overlayContext = context.navigationKey().currentState.overlay.context;
        return Center(
          child: TextButton(
              child: Text('Show dialog!'),
              onPressed: () {
                showDialog(
                    context: overlayContext, // use app level navigation context overlay
                    builder: (BuildContext context) {
                      return Dialog(
                        child: Text('Dialog.'),
                      );
                    });
              },
            ),
          );
      }
    }
    

    app_navkey.dart

    import 'package:flutter/widgets.dart';
    
    class AppNavKey extends InheritedWidget {
      final Widget child;
      final GlobalKey<NavigatorState> navigatorKey;
    
      AppNavKey({
        Key key,
        @required this.child,
        @required this.navigatorKey,
      }) : super(key: key, child: child);
    
      static GlobalKey<NavigatorState> of(BuildContext context) {
        final ctx = context.dependOnInheritedWidgetOfExactType<AppNavKey>();
        if (ctx == null) throw Exception('Could not find ancestor of type AppNavProvider');
        return ctx.navigatorKey;
      }
    
      @override
      bool updateShouldNotify(covariant InheritedWidget oldWidget) => false;
    }
    

    extensions.dart

    import 'package:flutter/widgets.dart';
    import 'package:myapp/app_navkey.dart';
    
    extension SwitchTabContext on BuildContext {
      /// Get app level NavigatorState key.
      /// ```dart
      /// context.navigationKey();
      /// ```
      GlobalKey<NavigatorState> navigationKey() => AppNavKey.of(this);
    }
    
        7
  •  0
  •   Rahul    5 年前

    如果你已经有了 context 对象,您可以通过 final rootContext = context.findRootAncestorStateOfType<NavigatorState>().context

    showDialog 或 showModalBottomSheet 上下文参数。