Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

showDialog from root widget

Tags:

flutter

I want to show a dialog from root widget (the one that created MaterialApp) I have a NavigatorState instance, but showDialog requires context that would return Navigator.of(context).

It looks like I need to provide context from a route, but I can't do this, because the root widget does not have it.

EDIT: I have found a workaround: I can push fake route that is only there to showDialog and then pop that route when dialog finishes. Not pretty but works.

like image 292
szotp Avatar asked Nov 14 '18 06:11

szotp


People also ask

How do I add showDialog to flutter?

In its on the pressed property, we have to use the showDialog widget of flutter. It takes context and a builder. In builder, we provide the AlertDialog widget with title, content(Description of a title), and actions (Yes or no buttons), and our alert dialog box is ready to use.

How do you fix navigator operation requested with a context that does not include a Navigator?

To solve this problem, we need to use a different context. In this situation, the easiest solution is to introduce a new widget as child of MaterialApp. And then use that widget's context to do the Navigator call. That's All.

How do I close dialog flutter?

pop(result) to close the dialog rather just Navigator. pop(context, result).


2 Answers

I fixed the problem by using navigatorKey.currentState.overlay.context. Here is example:

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,
          ),
        ),
      ),
    );
  }
}
like image 134
szotp Avatar answered Oct 28 '22 13:10

szotp


tl;dr: If you want to call showDialog from your root widget, extrude your code into another widget (e.g. a StatelessWidget), and call showDialog there.

Anyway, in the following I'm going to assume you are running into this issue:

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.

As said before, showDialog can only be called in a BuildContext whose ancestor has a MaterialApp. Therefore you can't directly call showDialogif you have a structure like this:

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

In a code example this would result in code like this, throwing the error given above:

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.'),
                      );
                    });
              }),
        ),
      ),
    );
  }
}

To solve this error from occuring you can create a new Widget, which has its own BuildContext. The modified structure would look like this:

- MaterialApp
  - Home

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

Modifying the code example to the structure given above, results in the code snippet below. showDialogcan be called without throwing the error.

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.'),
                    );
                  });
            }),
      ),
    );
  }
}
like image 32
NiklasPor Avatar answered Oct 28 '22 13:10

NiklasPor