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

如何确保同一时间仅打开一个Flutter MenuAnchor菜单?

解决Flutter MenuAnchor多菜单同时显示的问题

要实现右键点击新项目时自动关闭所有已打开的上下文菜单,不需要管理成百上千个MenuController,有两种简洁的方案:

方案1:利用Flutter焦点机制(推荐)

MenuAnchor打开的上下文菜单会自动获取焦点,我们可以通过让当前焦点控件失焦的方式,触发所有已打开的菜单关闭,再打开新菜单。

代码示例:

class ContextMenuItem extends StatefulWidget {
  final String name;
  const ContextMenuItem({super.key, required this.name});

  @override
  State<ContextMenuItem> createState() => _ContextMenuItemState();
}

class _ContextMenuItemState extends State<ContextMenuItem> {
  final _menuController = MenuController();

  @override
  void dispose() {
    _menuController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MenuAnchor(
      controller: _menuController,
      menuChildren: [
        MenuItemButton(
          child: Text('编辑 ${widget.name}'),
          onPressed: () => _menuController.close(),
        ),
        MenuItemButton(
          child: Text('删除 ${widget.name}'),
          onPressed: () => _menuController.close(),
        ),
      ],
      child: GestureDetector(
        onSecondaryTapDown: (details) {
          // 让当前焦点控件失焦,自动关闭所有已打开的菜单
          FocusManager.instance.primaryFocus?.unfocus();
          // 延迟执行确保其他菜单已完成关闭
          Future.microtask(() {
            _menuController.open(position: details.localPosition);
          });
        },
        child: Padding(
          padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
          child: Text(widget.name),
        ),
      ),
    );
  }
}

这个方案的优势是无需额外全局状态,完全依赖Flutter原生的焦点管理逻辑,代码量少且侵入性低。

方案2:全局状态通知(精准控制)

如果页面存在其他需要保留焦点的控件,可使用全局ValueNotifier来统一触发所有菜单的关闭操作:

  1. 定义全局通知器:
final globalMenuCloseTrigger = ValueNotifier<bool>(false);
  1. 每个菜单组件监听通知并响应:
class ContextMenuItem extends StatefulWidget {
  final String name;
  const ContextMenuItem({super.key, required this.name});

  @override
  State<ContextMenuItem> createState() => _ContextMenuItemState();
}

class _ContextMenuItemState extends State<ContextMenuItem> {
  late final MenuController _menuController;
  late VoidCallback _closeListener;

  @override
  void initState() {
    super.initState();
    _menuController = MenuController();
    _closeListener = () {
      if (_menuController.isOpen) {
        _menuController.close();
      }
    };
    globalMenuCloseTrigger.addListener(_closeListener);
  }

  @override
  void dispose() {
    globalMenuCloseTrigger.removeListener(_closeListener);
    _menuController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MenuAnchor(
      controller: _menuController,
      menuChildren: [
        MenuItemButton(
          child: Text('编辑 ${widget.name}'),
          onPressed: () => _menuController.close(),
        ),
        MenuItemButton(
          child: Text('删除 ${widget.name}'),
          onPressed: () => _menuController.close(),
        ),
      ],
      child: GestureDetector(
        onSecondaryTapDown: (details) {
          // 触发全局通知,关闭所有已打开的菜单
          globalMenuCloseTrigger.value = !globalMenuCloseTrigger.value;
          // 打开当前菜单
          _menuController.open(position: details.localPosition);
        },
        child: Padding(
          padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16),
          child: Text(widget.name),
        ),
      ),
    );
  }
}

该方案通过全局信号精准控制所有菜单的关闭状态,不会影响其他焦点控件,适合复杂页面场景。

内容的提问来源于stack exchange,提问作者Merritt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 05:24:59