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

如何在Flutter Web中实现鼠标悬停弹出PopupMenu菜单?

实现Flutter Web鼠标悬停弹出PopupMenu菜单

完全可行,默认的PopupMenuButton是点击触发,咱们可以通过MouseRegion监听鼠标的进入/离开事件,手动控制菜单的显示与隐藏。

下面是修改后的完整实现代码:

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

  @override
  State<HoverPopupMenu> createState() => _HoverPopupMenuState();
}

class _HoverPopupMenuState extends State<HoverPopupMenu> {
  // 记录菜单是否显示
  bool _isMenuOpen = false;
  // 用于获取按钮位置的全局key
  final GlobalKey _menuKey = GlobalKey();

  // 显示菜单
  void _showMenu() {
    if (_isMenuOpen) return;
    setState(() => _isMenuOpen = true);
    
    // 获取按钮的屏幕位置,确定菜单弹出的位置
    final RenderBox button = _menuKey.currentContext!.findRenderObject() as RenderBox;
    final RenderBox overlay = Overlay.of(context).context.findRenderObject() as RenderBox;
    final RelativeRect position = RelativeRect.fromRect(
      Rect.fromPoints(
        button.localToGlobal(Offset(0, button.size.height), ancestor: overlay),
        button.localToGlobal(button.size.bottomRight(Offset.zero), ancestor: overlay),
      ),
      Offset.zero & overlay.size,
    );

    // 弹出菜单,关闭后重置状态
    showMenu(
      context: context,
      position: position,
      color: const Color(0xFF262533),
      items: <PopupMenuEntry>[
        const PopupMenuItem(
          child: ListTile(
            title: Text(
              "Escortagenturen",
              style: TextStyle(color: Colors.white),
            ),
          ),
        ),
        const PopupMenuItem(
          child: ListTile(
            title: Text(
              "Bordelle",
              style: TextStyle(color: Colors.white),
            ),
          ),
        ),
        const PopupMenuItem(
          child: ListTile(
            title: Text(
              "Laufhauser",
              style: TextStyle(color: Colors.white),
            ),
          ),
        ),
        const PopupMenuItem(
          child: ListTile(
            title: Text(
              "Saunaclubs",
              style: TextStyle(color: Colors.white),
            ),
          ),
        ),
        const PopupMenuItem(
          child: ListTile(
            title: Text(
              "Domina & BDSM-Studios",
              style: TextStyle(color: Colors.white),
            ),
          ),
        ),
        const PopupMenuItem(
          child: ListTile(
            title: Text(
              "Tantra & Massaage-Studios",
              style: TextStyle(color: Colors.white),
            ),
          ),
        ),
      ],
    ).then((_) {
      setState(() => _isMenuOpen = false);
    });
  }

  // 隐藏菜单
  void _hideMenu() {
    if (_isMenuOpen) {
      Navigator.of(context).pop();
      setState(() => _isMenuOpen = false);
    }
  }

  @override
  Widget build(BuildContext context) {
    return MouseRegion(
      key: _menuKey,
      onEnter: (_) => _showMenu(),
      onExit: (_) => _hideMenu(),
      child: const Text(
        "Agenturen & Clubs",
        style: TextStyle(
          color: Colors.white,
          fontSize: 24,
          fontFamily: "Poppins",
        ),
      ),
    );
  }
}

关键细节说明:

  • 用MouseRegion包裹触发文本,监听鼠标进入/离开事件,分别触发菜单的显示和隐藏。
  • 通过GlobalKey获取按钮的屏幕位置,确保菜单在按钮下方弹出(和你原本设置的PopupMenuPosition.under效果一致)。
  • 手动调用showMenu替代默认的点击触发逻辑,菜单关闭后自动重置状态,避免重复触发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 05:25:36