showDialog bug: dialog isn't triggered from PopupMenuButton in Flutter
Solution 1
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'),
),
));
},
)
Solution 2
There is an easier way to achieve it using the actual functionality of PopupMenuButton
.
Just give a value
to you PopUpMenuItem
and check for it on the onSelected
callback from PopupMenuButton
as follows:
PopupMenuButton<String>(
onSelected: (value) async {
switch (value) {
case 'open_dialog':
return showDialog(...);
default:
throw UnimplementedError();
}
},
itemBuilder: (context) => [
const PopupMenuItem(
child: Text('Open dialog'),
value: 'open_dialog',
),
],
),
This way you will consume the parent context
and not the itemBuilder context
that gets popped on tap as mentioned here. Then decide what to execute when that value is received, for example, opening the dialog.
You can also use an enum
instead of String
as values if you want to have it properly type safe.
Comments
-
kamalbanga over 1 year
I am not able to get
showDialog
work withPopupMenuButton
. 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'), ));