showDialog 错误:Flutter 中的 PopupMenuButton 不会触发对话框

我无法让 showDialogPopupMenuButton 一起工作。在下面的示例中,有一个按钮可以触发要显示的对话框,而弹出菜单也可以触发要显示的对话框。

该按钮有效,但单击 PopupMenu 中的 Alert 文本时,不会发生同样的情况。

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

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

showDialog(
context: context,
builder: (ctx) => AlertDialog(
      title: Text('test dialog'),
    ));
stack overflow showDialog bug: dialog isn't triggered from PopupMenuButton in Flutter
原文答案
author avatar

接受的答案

这不是一个错误。我记得, onTapPopupMenuItem 回调调用 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'),
        ),
      ),
    );
  },
)

答案:

作者头像

使用 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',
    ),
  ],
),

这样,您将使用 parent context 而不是 itemBuilder context ,它会在点击时弹出为 mentioned here 。然后决定在收到该值时执行什么,例如打开对话框。

如果您想让它正确类型安全,您也可以使用 enum 而不是 String 作为值。

作者头像

试试下面的代码:

PopupMenuItem(
  value: val,
  child: InkWell(
    onTap: opendialog() ?? () {},
    child: Container(
      height: 20,
      child: Row(
        children: [
          AppText(
            text: "Text",
            color: Colors.black38,
          ),
        ],
      ),
    ),
  ),
),