showDialog bug:Flutter 中的 PopupMenuButton 未触发对话框

kam*_*nga 19 widget android-alertdialog dart flutter

我无法找到showDialog工作PopupMenuButton。在下面的示例中,有一个触发对话框显示的按钮和一个弹出菜单也触发对话框显示。

该按钮可以工作,但单击PopupMenu 中的警报文本时,不会发生同样的情况。

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')));
  }
}
Run Code Online (Sandbox Code Playgroud)

但是,当我添加另一个showDialog后续块时,它开始工作。

showDialog(
context: context,
builder: (ctx) => AlertDialog(
      title: Text('test dialog'),
    ));
Run Code Online (Sandbox Code Playgroud)

Kan*_*n48 46

这不是一个错误。我记得,关闭弹出窗口onTap的调用的PopupMenuItem回调。Navigator.pop在这种情况下,当您点击PopupMenuItem并调用时showDialog,对话框将立即弹出,并使弹出窗口保持打开状态。

为了克服这个问题,您可以尝试以下解决方案:

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


小智 16

有一种更简单的方法可以使用 的实际功能来实现它PopupMenuButton

value只需给您一个并在回调PopUpMenuItem中检查它,如下所示:onSelectedPopupMenuButton

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',
    ),
  ],
),
Run Code Online (Sandbox Code Playgroud)

这样您将消耗parent context而不是像这里提到的itemBuilder context那样在水龙头上弹出的。然后决定收到该值时要执行的操作,例如打开对话框。

如果您想让它正确地类型安全,您也可以使用 anenum代替as 值。String

  • 这应该是最好的答案。 (3认同)