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

Flutter 3.7.0鼠标悬停子菜单无法持续显示的问题求助

Flutter 3.7.0 悬停子菜单无法保持显示的解决方案

问题分析

你的代码核心问题在于:当鼠标从主按钮移到子菜单时,主按钮的onHover会触发离开状态,启动延迟关闭菜单的逻辑;而子菜单的onHover调用open()的时机无法阻止这个延迟关闭,同时嵌套的TextButton会干扰菜单的事件处理,导致子菜单无法保持显示。

修复方案

通过以下几点调整解决问题:

  • 用计时器统一管理菜单的关闭时机,只有当鼠标完全离开主按钮和子菜单区域一段时间后才关闭菜单
  • 移除MenuItemButton内部嵌套的TextButton,避免事件冲突
  • 优化主按钮和子菜单的hover事件逻辑,联动控制计时器

修改后的完整代码

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

void main() => runApp(const MenuBarApp());

class MyMenuBar extends StatefulWidget implements PreferredSizeWidget {
  const MyMenuBar({super.key});

  @override
  State<MyMenuBar> createState() => _MyMenuBarState();

  @override
  Size get preferredSize => const Size.fromHeight(kToolbarHeight);
}

class _MyMenuBarState extends State<MyMenuBar> {
  final MenuController _menuController = MenuController();
  Timer? _closeTimer;

  @override
  void dispose() {
    _closeTimer?.cancel();
    super.dispose();
  }

  // 取消关闭计时器
  void _cancelCloseTimer() {
    if (_closeTimer?.isActive ?? false) {
      _closeTimer!.cancel();
    }
  }

  // 启动关闭计时器(300ms后关闭菜单)
  void _startCloseTimer() {
    _cancelCloseTimer();
    _closeTimer = Timer(const Duration(milliseconds: 300), () {
      if (_menuController.isOpen) {
        _menuController.close();
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        MenuAnchor(
          controller: _menuController,
          style: const MenuStyle(
            backgroundColor: MaterialStatePropertyAll<Color>(Colors.black),
            padding: MaterialStatePropertyAll<EdgeInsets>(EdgeInsets.all(8)),
          ),
          menuChildren: _getMenus(),
          builder: (context, controller, child) {
            return TextButton(
              child: const Text("Home"),
              onPressed: () {},
              onHover: (isHovered) {
                if (isHovered) {
                  _cancelCloseTimer();
                  if (!controller.isOpen) {
                    controller.open();
                  }
                } else {
                  _startCloseTimer();
                }
              },
            );
          },
        ),
      ],
    );
  }

  List<Widget> _getMenus() {
    return [
      MenuItemButton(
        onHover: (isHovered) {
          if (isHovered) {
            _cancelCloseTimer();
          } else {
            _startCloseTimer();
          }
        },
        onPressed: () {},
        child: const Text(
          "About",
          textAlign: TextAlign.left,
          overflow: TextOverflow.ellipsis,
          style: TextStyle(
            fontSize: 16,
            fontWeight: FontWeight.w500,
            color: Colors.white,
          ),
        ),
      ),
    ];
  }
}

class MenuBarApp extends StatelessWidget {
  const MenuBarApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Scaffold(appBar: MyMenuBar()),
    );
  }
}

关键改动说明

  • 添加Timer? _closeTimer变量,用于延迟关闭菜单,避免鼠标在主按钮和子菜单之间切换时误关闭
  • 新增_cancelCloseTimer()和_startCloseTimer()方法,统一管理计时器的启动和取消
  • 主按钮的onHover逻辑:鼠标悬停时取消计时器并打开菜单;离开时启动计时器
  • 子菜单的onHover逻辑:鼠标悬停时取消计时器;离开时启动计时器,确保只有完全离开菜单区域才关闭
  • 移除MenuItemButton内部的TextButton,直接使用Text作为子组件,避免事件穿透和冲突

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 18:01:09