Search code examples
flutterdartwidgetandroid-alertdialog

showDialog bug: dialog isn't triggered from PopupMenuButton in Flutter


I am not able to get showDialog work with PopupMenuButton. In the example below, there is a button with triggering a dialog to display and a popupmenu too triggering a dialog to display.

The button works but on clicking on the Alert text in PopupMenu, the same doesn't happen.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text('showDialog bug'), actions: [
          PopupMenuButton(
              itemBuilder: (ctx) => [
                    PopupMenuItem(
                        child: Text('Alert'),
                        onTap: () {
                          showDialog(
                              context: context,
                              builder: (ctx) => AlertDialog(
                                    title: Text('test dialog'),
                                  ));
                        })
                  ])
        ]),
        body: ElevatedButton(
            onPressed: () {
              showDialog(
                  context: context,
                  builder: (ctx) => AlertDialog(
                        title: Text('test dialog'),
                      ));
            },
            child: Text('click me')));
  }
}

However, when I add another block of showDialog subsequent to it, it starts working.

showDialog(
context: context,
builder: (ctx) => AlertDialog(
      title: Text('test dialog'),
    ));

Solution

  • It's not a bug. As I remember, the onTap callback of PopupMenuItem calls Navigator.pop to close the Popup. In that case, when you tap on the PopupMenuItem and call showDialog, the Dialog will be popped immediately, and leaves the Popup open.

    In order to overcome that, you may try this solution :

    PopupMenuItem(
      child: const Text('Alert'),
      onTap: () {
        Future.delayed(
          const Duration(seconds: 0),
          () => showDialog(
            context: context,
            builder: (context) => const AlertDialog(
              title: Text('test dialog'),
            ),
          ),
        );
      },
    )