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

Flutter导航栏用户名称项添加自定义子菜单方案咨询

实现导航栏用户项的可自定义子菜单(复用SidebarItem)

1. 封装通用下拉菜单容器

先做一个可复用的下拉菜单组件,负责处理展开/收起动画和触发逻辑,专门用来包裹你已有的SidebarItem:

class CustomDropdownMenu extends StatefulWidget {
  final Widget trigger; // 触发子菜单的导航栏用户项
  final List<Widget> items; // 自定义子菜单项(传入SidebarItem)
  final Duration animationDuration;

  const CustomDropdownMenu({
    super.key,
    required this.trigger,
    required this.items,
    this.animationDuration = const Duration(milliseconds: 300),
  });

  @override
  State<CustomDropdownMenu> createState() => _CustomDropdownMenuState();
}

class _CustomDropdownMenuState extends State<CustomDropdownMenu> with SingleTickerProviderStateMixin {
  bool _isExpanded = false;
  late Animation<double> _expandAnimation;
  late AnimationController _animationController;

  @override
  void initState() {
    super.initState();
    _animationController = AnimationController(
      duration: widget.animationDuration,
      vsync: this,
    );
    _expandAnimation = Tween<double>(begin: 0, end: 1).animate(
      CurvedAnimation(parent: _animationController, curve: Curves.easeInOut),
    );
  }

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

  void _toggleMenu() {
    setState(() {
      _isExpanded = !_isExpanded;
      _isExpanded ? _animationController.forward() : _animationController.reverse();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        // 触发按钮:绑定点击事件的用户名称项
        InkWell(
          onTap: _toggleMenu,
          child: widget.trigger,
        ),
        // 动画展开的子菜单容器
        SizeTransition(
          sizeFactor: _expandAnimation,
          axisAlignment: 1.0,
          child: Container(
            margin: const EdgeInsets.only(top: 8),
            decoration: BoxDecoration(
              color: Theme.of(context).cardColor,
              borderRadius: BorderRadius.circular(8),
              boxShadow: [
                BoxShadow(
                  color: Colors.grey.withOpacity(0.2),
                  blurRadius: 4,
                  offset: const Offset(0, 2),
                ),
              ],
            ),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: widget.items,
            ),
          ),
        ),
      ],
    );
  }
}

2. 集成到导航栏,复用SidebarItem

假设你的SidebarItem是如下样式(匹配你提到的AnimatedContainer风格):

class SidebarItem extends StatelessWidget {
  final String title;
  final VoidCallback onTap;
  final bool isActive;

  const SidebarItem({
    super.key,
    required this.title,
    required this.onTap,
    this.isActive = false,
  });

  @override
  Widget build(BuildContext context) {
    return AnimatedContainer(
      duration: const Duration(milliseconds: 200),
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
      margin: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
      decoration: BoxDecoration(
        color: isActive ? Colors.blue.withOpacity(0.1) : Colors.transparent,
        borderRadius: BorderRadius.circular(8),
      ),
      child: InkWell(
        onTap: onTap,
        child: Text(
          title,
          style: TextStyle(
            color: isActive ? Colors.blue : Colors.black87,
            fontSize: 14,
            fontWeight: isActive ? FontWeight.w500 : FontWeight.normal,
          ),
        ),
      ),
    );
  }
}

然后在导航栏的用户项位置,替换为CustomDropdownMenu,直接传入SidebarItem作为子菜单:

// 导航栏中的用户名称项替换为以下代码
CustomDropdownMenu(
  trigger: NavbarItem(
    title: user.firstName, // 你的用户名称变量
    icon: const Icon(Icons.person), // 保留原导航栏项的样式
  ),
  items: [
    SidebarItem(
      title: "修改密码",
      onTap: () {
        // 这里写修改密码的逻辑,比如跳转页面
        Navigator.push(context, MaterialPageRoute(builder: (_) => const ChangePasswordPage()));
      },
    ),
    SidebarItem(
      title: "更新信息",
      onTap: () {
        // 这里写更新用户信息的逻辑
        Navigator.push(context, MaterialPageRoute(builder: (_) => const UpdateProfilePage()));
      },
    ),
    // 后续可随时添加更多自定义子菜单项
  ],
)

3. 常见问题处理

  • 点击外部收起菜单:如果需要点击页面其他区域自动收起菜单,可以在CustomDropdownMenu的build最外层套一个GestureDetector:
GestureDetector(
  onTap: () {
    if (_isExpanded) _toggleMenu();
  },
  behavior: HitTestBehavior.translucent,
  child: // 原Column内容
)
  • 水平导航栏适配:如果导航栏是水平布局,子菜单可能需要用Positioned包裹,避免影响导航栏的布局流,比如将子菜单容器放在Stack中定位。
  • 状态同步:如果用户名称是全局状态,建议用Provider/Riverpod等状态管理工具,确保用户信息更新时导航栏能同步刷新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 20:00:13