Menu

在不通过修改布局、大小或位置的情况下,对子组件施加虚拟效果的组件

Menu是Flutter中的一个菜单组件,用于在用户交互(如点击按钮)时显示一个下拉或弹出式菜单列表。它基于MenuAnchorMenuItemButton构建,支持嵌套子菜单、快捷键、图标集成等功能,适用于 应用栏、上下文菜单或自定义界面中的选项选择。Menu的核心逻辑是动态管理菜单的打开/关闭状态,并通过回调处理用户选择。

使用场景

  • 应用栏菜单: 在AppBaractions中提供设置、帮助等选项。
  • 上下文菜单: 长按某区域时弹出编辑、删除等操作。
  • 嵌套菜单: 用于复杂工作流(如设计工具中的多级菜单)。
  • 快捷键集成: 为菜单项绑定键盘快捷键(如Ctrl+S保存)。

示例

基础菜单

import 'package:flutter/material.dart';

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

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

  
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Menu 示例'),
          actions: [
            MenuAnchor(
              child: IconButton(
                icon: const Icon(Icons.more_vert),
                onPressed: () {}, // 由 MenuAnchor 自动处理点击
              ),
              menuChildren: [
                MenuItemButton(
                  child: const Text('设置'),
                  onPressed: () => print('打开设置'),
                ),
                MenuItemButton(
                  child: const Text('帮助'),
                  onPressed: () => print('打开帮助'),
                ),
              ],
            ),
          ],
        ),
        body: const Center(child: Text('点击右上角菜单图标试试!')),
      ),
    );
  }
}

嵌套子菜单

MenuAnchor(
  child: TextButton(
    child: const Text('文件'),
    onPressed: () {},
  ),
  menuChildren: [
    MenuItemButton(
      child: const Text('新建'),
      onPressed: () => print('新建文件'),
    ),
    SubmenuButton(
      menuChildren: [
        MenuItemButton(
          child: const Text('保存'),
          onPressed: () => print('保存文件'),
        ),
        MenuItemButton(
          child: const Text('另存为'),
          onPressed: () => print('另存为'),
        ),
      ],
      child: const Text('保存选项'),
    ),
  ],
)

带图标和快捷键的菜单

MenuAnchor(
  child: const Icon(Icons.settings),
  menuChildren: [
    MenuItemButton(
      leadingIcon: const Icon(Icons.save),
      child: const Text('保存'),
      onPressed: () => print('保存操作'),
      shortcut: const SingleActivator(LogicalKeyboardKey.keyS, control: true),
    ),
    MenuItemButton(
      leadingIcon: const Icon(Icons.exit_to_app),
      child: const Text('退出'),
      onPressed: () => print('退出应用'),
    ),
  ],
)

注意点

常见问题

  • 状态管理: 菜单的打开状态由MenuController控制,需避免在多个组件中冲突。
  • 性能影响: 嵌套过深或菜单项过多可能导致渲染延迟,建议使用ConstrainedBox限制菜单大小。
  • 兼容性: Menu需要Flutter 3.10+版本,旧项目需升级SDK。

优化技巧

  • 为频繁使用的菜单添加Key以避免不必要的重建。
  • 使用MenuStyle自定义主题,确保与应用风格一致。
  • 在窄屏幕设备上测试菜单的响应式布局(如自动调整位置)。

最佳实践

  • 菜单项文本应简洁明了,配合图标提升可读性。
  • 禁用当前不可用的菜单项(通过MenuItemButtonenabled参数)。
  • 优先使用SubmenuButton而非手动嵌套,以保持逻辑清晰。

构造函数

const MenuAnchor({
  Key? key,
  required this.child, // 触发菜单的控件(如按钮)
  required this.menuChildren, // 菜单项列表
  this.onOpen, // 菜单打开回调
  this.onClose, // 菜单关闭回调
  this.controller, // 控制菜单状态的 MenuController
  this.style, // 自定义菜单样式(MenuStyle)
})
const MenuItemButton({
  Key? key,
  required this.onPressed, // 菜单项点击回调
  this.child, // 菜单项文本或自定义控件
  this.leadingIcon, // 前置图标
  this.trailingIcon, // 后置图标
  this.shortcut, // 键盘快捷键
  this.enabled = true, // 是否启用
})

属性

属性名属性类型说明
childWidget触发菜单的控件(必选)。
menuChildrenList<Widget>菜单项列表(通常为 MenuItemButtonSubmenuButton)。
onOpenVoidCallback?菜单打开时触发的回调。
onCloseVoidCallback?菜单关闭时触发的回调。
controllerMenuController?用于编程控制菜单状态(如主动打开/关闭)。
styleMenuStyle?自定义菜单的外观(背景色、阴影等)。
onPressedVoidCallback?MenuItemButton 的点击事件回调(若为 null,菜单项显示为禁用状态)。
leadingIconWidget?MenuItemButton 的前置图标(如 Icons.save)。
shortcutShortcut?绑定键盘快捷键(如 SingleActivator(LogicalKeyboardKey.keyS))。
enabledbool控制 MenuItemButton 是否可交互(默认 true)。

关键属性解释

  • menuChildren: 必须包含有效的菜单项组件,否则菜单无法显示内容。支持动态生成列表(如基于数据循环生成)。
  • controller: 通过MenuController可实现跨组件控制菜单(如点击其他区域关闭菜单),适合复杂交互场景。
  • shortcut: 快捷键需在父级配置Shortcuts组件才能生效,是提升专业应用体验的核心功能。