You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中点击IconButton时如何弹出PopupMenu?

问题分析

你现在的代码无法弹出菜单的核心原因是:PopupMenuButton是一个Widget,必须被添加到Flutter的Widget树中才能渲染,而你在IconButton的onPressed回调里直接实例化它,并不会将其插入到Widget树里,所以菜单不会显示。


解决方案

方案1:直接用PopupMenuButton替代IconButton(推荐)

PopupMenuButton本身支持自定义触发图标,不需要额外套一层IconButton,代码更简洁,也符合Flutter组件的设计逻辑:

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

String _selectedMenu = '';

enum Menu { itemOne, itemTwo, itemThree, itemFour }

class ListTileWithIcon extends StatefulWidget {
  const ListTileWithIcon({super.key});

  @override
  State<ListTileWithIcon> createState() => _ListTileWithIconState();
}

class _ListTileWithIconState extends State<ListTileWithIcon> {
  @override
  Widget build(BuildContext context) {
    return ListTile(
      leading: const Icon(Icons.person),
      title: const Text("The ListTile"),
      // 直接用PopupMenuButton作为trailing,替代IconButton
      trailing: PopupMenuButton<Menu>(
        splashRadius: 20,
        // 设置触发菜单的图标
        icon: const Icon(
          Icons.more_vert_rounded,
          size: 20.0,
          color: Color.fromARGB(255, 135, 0, 212),
        ),
        onSelected: (Menu item) {
          setState(() {
            _selectedMenu = item.name;
          });
        },
        itemBuilder: (BuildContext context) => <PopupMenuEntry<Menu>>[
          const PopupMenuItem<Menu>(
            value: Menu.itemOne,
            child: Text('Item 1'),
          ),
          const PopupMenuItem<Menu>(
            value: Menu.itemTwo,
            child: Text('Item 2'),
          ),
          const PopupMenuItem<Menu>(
            value: Menu.itemThree,
            child: Text('Item 3'),
          ),
          const PopupMenuItem<Menu>(
            value: Menu.itemFour,
            child: Text('Item 4'),
          ),
        ],
      ),
      onTap: () {},
    );
  }
}

方案2:保留IconButton,手动调用showMenu弹出菜单

如果一定要保留IconButton,可以通过showMenu方法手动触发菜单弹出,需要先计算菜单的弹出位置:

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

String _selectedMenu = '';

enum Menu { itemOne, itemTwo, itemThree, itemFour }

class ListTileWithIcon extends StatefulWidget {
  const ListTileWithIcon({super.key});

  @override
  State<ListTileWithIcon> createState() => _ListTileWithIconState();
}

class _ListTileWithIconState extends State<ListTileWithIcon> {
  @override
  Widget build(BuildContext context) {
    return ListTile(
      leading: const Icon(Icons.person),
      title: const Text("The ListTile"),
      trailing: IconButton(
        splashRadius: 20,
        icon: const Icon(
          Icons.more_vert_rounded,
          size: 20.0,
          color: Color.fromARGB(255, 135, 0, 212),
        ),
        onPressed: () async {
          if (kDebugMode) {
            print("Inside icon button's click");
          }

          // 获取按钮在屏幕上的位置
          final RenderBox button = context.findRenderObject() as RenderBox;
          final RenderBox overlay = Overlay.of(context).context.findRenderObject() as RenderBox;
          final RelativeRect position = RelativeRect.fromRect(
            Rect.fromPoints(
              button.localToGlobal(Offset.zero, ancestor: overlay),
              button.localToGlobal(button.size.bottomRight(Offset.zero), ancestor: overlay),
            ),
            Offset.zero & overlay.size,
          );

          // 弹出菜单并获取选择结果
          final Menu? selectedItem = await showMenu<Menu>(
            context: context,
            position: position,
            items: <PopupMenuEntry<Menu>>[
              const PopupMenuItem<Menu>(
                value: Menu.itemOne,
                child: Text('Item 1'),
              ),
              const PopupMenuItem<Menu>(
                value: Menu.itemTwo,
                child: Text('Item 2'),
              ),
              const PopupMenuItem<Menu>(
                value: Menu.itemThree,
                child: Text('Item 3'),
              ),
              const PopupMenuItem<Menu>(
                value: Menu.itemFour,
                child: Text('Item 4'),
              ),
            ],
          );

          if (selectedItem != null) {
            setState(() {
              _selectedMenu = selectedItem.name;
            });
          }
        },
      ),
      onTap: () {},
    );
  }
}

内容的提问来源于stack exchange,提问作者Abdul Haadi Alhassan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 04:30:48