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

Flutter Material 3实现类似Atlassian的AppBar用户头像下拉菜单

实现Material3风格的Atlassian式用户下拉菜单

针对你的需求,下面提供手动基于MenuAnchor扩展实现和第三方包替代两种方案:

一、手动实现(基于Material3的MenuAnchor)

MenuAnchor本身支持自定义menuChildren,你可以通过嵌套Column、Text、Divider、MenuItemButton等Widget来构建分区、标题和不可点击区域,完全不需要依赖第三方包:

完整代码示例

AppBar(
  actions: [
    MenuAnchor(
      builder: (context, controller, child) {
        return IconButton(
          icon: const CircleAvatar(
            backgroundImage: NetworkImage('你的头像URL'),
          ),
          onPressed: () {
            controller.isOpen ? controller.close() : controller.open();
          },
        );
      },
      menuChildren: [
        // 不可点击的账户信息区域(蓝色标记)
        Padding(
          padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisSize: MainAxisSize.min,
            children: [
              Text(
                'Guiu Mateu',
                style: Theme.of(context).textTheme.titleMedium,
              ),
              const SizedBox(height: 4),
              Text(
                'guiu@example.com',
                style: Theme.of(context).textTheme.bodySmall?.copyWith(
                      color: Theme.of(context).colorScheme.onSurfaceVariant,
                    ),
              ),
            ],
          ),
        ),
        // 分区分隔线
        const Divider(height: 1),
        // 第一个分区:账户(绿色标记)
        Padding(
          padding: const EdgeInsets.only(left: 16, top: 12, bottom: 8),
          child: Text(
            '账户', // 分区标题(黄色标记)
            style: Theme.of(context).textTheme.labelSmall?.copyWith(
                  color: Theme.of(context).colorScheme.onSurfaceVariant,
                  fontWeight: FontWeight.w500,
                ),
          ),
        ),
        MenuItemButton(
          leadingIcon: const Icon(Icons.person_outline),
          child: const Text('查看个人资料'),
          onPressed: () {},
        ),
        MenuItemButton(
          leadingIcon: const Icon(Icons.settings_outlined),
          child: const Text('账户设置'),
          onPressed: () {},
        ),
        // 分区分隔线
        const Divider(height: 1),
        // 第二个分区:最近工作区(绿色标记)
        Padding(
          padding: const EdgeInsets.only(left: 16, top: 12, bottom: 8),
          child: Text(
            '最近工作区', // 分区标题(黄色标记)
            style: Theme.of(context).textTheme.labelSmall?.copyWith(
                  color: Theme.of(context).colorScheme.onSurfaceVariant,
                  fontWeight: FontWeight.w500,
                ),
          ),
        ),
        MenuItemButton(
          leadingIcon: const Icon(Icons.work_outline),
          child: const Text('项目A工作区'),
          onPressed: () {},
        ),
        MenuItemButton(
          leadingIcon: const Icon(Icons.work_outline),
          child: const Text('个人沙箱'),
          onPressed: () {},
        ),
        // 底部退出按钮分区
        const Divider(height: 1),
        MenuItemButton(
          leadingIcon: const Icon(Icons.logout),
          child: const Text('退出登录'),
          style: MenuItemButton.styleFrom(
            foregroundColor: Theme.of(context).colorScheme.error,
          ),
          onPressed: () {},
        ),
      ],
    ),
  ],
)

关键实现点说明

  • 不可点击区域:直接用Padding+Column包裹文本,不添加任何点击回调,通过主题文本样式适配Material3风格
  • 分区标题:用Text组件配合labelSmall文本样式,颜色设为onSurfaceVariant,添加左侧内边距实现对齐
  • 分区分隔:用Divider组件实现分区之间的分割线,和Atlassian的样式一致
  • 菜单交互:保留MenuItemButton实现可点击菜单项,保证Material3的交互一致性

二、第三方包替代方案

如果不想手动布局,可以使用popover包,它支持完全自定义下拉内容,适配Material3风格:

使用步骤

  1. 添加依赖到pubspec.yaml:
dependencies:
  popover: ^0.2.8
  1. 实现示例
AppBar(
  actions: [
    Popover(
      bodyBuilder: (context) => SizedBox(
        width: 280,
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            // 不可点击的账户信息区域
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text('Guiu Mateu', style: Theme.of(context).textTheme.titleMedium),
                  const SizedBox(height: 4),
                  Text('guiu@example.com', style: Theme.of(context).textTheme.bodySmall?.copyWith(color: Theme.of(context).colorScheme.onSurfaceVariant)),
                ],
              ),
            ),
            const Divider(height: 1),
            // 账户分区
            Padding(
              padding: const EdgeInsets.only(left: 16, top: 12, bottom: 8),
              child: Text('账户', style: Theme.of(context).textTheme.labelSmall?.copyWith(color: Theme.of(context).colorScheme.onSurfaceVariant, fontWeight: FontWeight.w500)),
            ),
            ListTile(
              leading: const Icon(Icons.person_outline),
              title: const Text('查看个人资料'),
              onTap: () {
                Navigator.pop(context);
                // 执行操作
              },
            ),
            // 后续分区和内容同上...
          ],
        ),
      ),
      direction: PopoverDirection.bottom,
      child: const CircleAvatar(
        backgroundImage: NetworkImage('你的头像URL'),
      ),
    ),
  ],
)

这个包的优势是可以更灵活地控制下拉菜单的位置、大小和内容样式,不需要受限于MenuAnchor的默认布局。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 18:15:01