如何在单击图标按钮小部件的位置显示弹出菜单

我制作了一个警报对话框,用户可以在其中更新他们的个人资料详细信息。在图像容器中,有图标按钮小部件。我想要的是,当用户单击图标按钮时,弹出菜单将显示添加/删除图像选项。这是我的警报对话框代码:

showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
  return AlertDialog(
      title: Text('Edit detail'),
      content: StatefulBuilder(
        builder: (context, setState) {
          return Container(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: <Widget>[
                Stack(
                    alignment: Alignment.center,
                    children: [
                      Container(
                        //image container
                      ),
                      GestureDetector(
                        // the pop up menu displays away from alert dialog
                        onTapDown: (TapDownDetails details) {
                          if (imageData != null) {
                            _showPopupMenu(details.globalPosition);
                            print('choose image/remove image');
                          } else {}
                        },
                        child: IconButton(icon: Icon(Icons.edit),
                            onPressed: () async {}),
                      )
                    ]),
              ],
            ),
          );
        },
      ),
      actions: <Widget>[
    //action button
  )],
  );
},);

这是弹出菜单的代码。

void _showPopupMenu(Offset offset) async {
double left = offset.dx;
double top = offset.dy;
await showMenu<String>(
  context: context,
  position: RelativeRect.fromLTRB(left, top, 0.0, 0.0),      //position where want to show the menu on screen
  items: [
    PopupMenuItem<String>(
        child: const Text('Add image'), value: '1'),
    PopupMenuItem<String>(
        child: const Text('Delete image'), value: '2'),
  ],
  elevation: 8.0,
)
    .then<void>((String itemSelected) {

  if (itemSelected == null) return;

  if(itemSelected == "1"){
  } else {
  }

});}

菜单显示在警报对话框之外。我看过类似的带有手势检测器的帖子,但我似乎无法理解我的错误。请帮助我,欢迎任何改进。提前致谢。

stack overflow How to show pop up menu where icon button widget is clicked
原文答案

答案:

作者头像

您可以使用 AlertDialog 和 IconButton 的键来执行此操作,如下所示

 GlobalKey cKey = new GlobalKey();
 GlobalKey pKey = new GlobalKey();

  void _showPopupMenu() async {
    await showMenu<String>(
      context: context,
      position: RelativeRect.fromRect(_getWidgetGlobalRect(pKey),_getWidgetGlobalRect(cKey)),
      items: [
        PopupMenuItem<String>(child: const Text('Add image'), value: '1'),
        PopupMenuItem<String>(child: const Text('Delete image'), value: '2'),
      ],
      elevation: 8.0,
    ).then<void>((String itemSelected) {
      if (itemSelected == null) return;

      if (itemSelected == "1") {
      } else {}
    });
  }

  Rect _getWidgetGlobalRect(GlobalKey key) {
    RenderBox renderBox = key.currentContext.findRenderObject();
    var offset = renderBox.localToGlobal(Offset.zero);
    return Rect.fromLTWH(
        offset.dx, offset.dy, renderBox.size.width, renderBox.size.height);
  }

  void showDialig() {
    showDialog<void>(
      context: context,
      barrierDismissible: false, // user must tap button!
      builder: (BuildContext context) {
        return AlertDialog(
          key: cKey,
          title: Text('Edit detail'),
          content: StatefulBuilder(
            builder: (context, setState) {
              return Container(
                child: Column(

                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: <Widget>[
                    Stack(alignment: Alignment.topRight, children: [

                      Container(
                          //image container
                          ),
                      GestureDetector(
                        // the pop up menu displays away from alert dialog
                        onTapDown: (TapDownDetails details) {
                          _showPopupMenu();
                        },
                        child: IconButton(
                            key: pKey,
                            icon: Icon(Icons.edit),
                            onPressed: () async {}),
                      )
                    ]),
                  ],
                ),
              );
            },
          ),
          actions: <Widget>[
            //action button
          ],
        );
      },
    );
  }
作者头像

如果您使用的是 GestureDetector,我刚刚做了一个简单的方法,只需将一个 GestureDetector 放在另一个 GestureDetector 中,然后设置 onTap 操作(如果您在两个 GestureDetector 上都是这种情况),不同之处在于您要执行一个操作,一个在另一个中,您可以将其留空,就像这样。

GestureDetector(
    onTap: () { //The Gesture you dont want to afect the rest
      Navigator.pop(context);
    },
    child: Container(
      color: Colors.transparent,
      child:GestureDetector(
            onTap: () {}, //This way is not going to afect the inside widget
            child: Container() //your widget
            )
          )
        )