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

Flutter侧边栏菜单无法匹配参考设计,求修改方案

Flutter侧边栏菜单复刻问题

问题描述

我正在Flutter中开发侧边栏菜单,尝试复刻参考设计的外观与交互效果,但当前实现无法达到预期效果。

参考设计

  • SideBarMenuTileDesgin-1
  • SideBarMenuTileDesign-2

当前实现效果

  • SideBarMenuUi

当前代码

bool _isHovered = false;
int _selectedActivityLogIndex = 0;
int _selectedSidebarIndex = 0;

void _setHovered(bool isHovered) {
  setState(() {
    _isHovered = isHovered;
  });
}

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: Row(
      children: [
        MouseRegion(
          onEnter: (_) => _setHovered(true),
          onExit: (_) => _setHovered(false),
          child: AnimatedContainer(
            duration: const Duration(milliseconds: 300),
            width: _isHovered ? 200.0 : 60.0,
            color: AppColors.sideBarMenuColor,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                _buildSidebarItem(SideBarMenuIcons.applicantSideMenuIcon1, 'Overview', 0),
                _buildSidebarItem(SideBarMenuIcons.applicantSideMenuIcon7, 'DBS', 1),
                _buildSidebarItem(SideBarMenuIcons.applicantSideMenuIcon6, 'Basic Disclosure', 2),
                _buildSidebarItem(SideBarMenuIcons.applicantSideMenuIcon5, 'Reference Check', 3),
                _buildSidebarItem(SideBarMenuIcons.applicantSideMenuIcon4, 'Right to Work', 4),
                _buildSidebarItem(SideBarMenuIcons.applicantSideMenuIcon3, 'Qualification', 5),
                _buildSidebarItem(SideBarMenuIcons.applicantSideMenuIcon2, 'ID', 6),
              ],
            ),
          ),
        ),
        Expanded(
          flex: 6,
          child: SingleChildScrollView(
            padding: const EdgeInsets.all(20.0),
            child: _buildContent(_selectedSidebarIndex),
          ),
        ),
      ],
    ),
  );
}

Widget _buildSidebarItem(String assetPath, String title, int index) {
  final isSelected = index == _selectedSidebarIndex;

  return GestureDetector(
    onTap: () {
      setState(() {
        _selectedSidebarIndex = index;
      });
    },
    child: Container(
      decoration: BoxDecoration(
        borderRadius: BorderRadius.only(
          bottomRight: Radius.circular(isSelected ? 20.0 : 0.0),
          topRight: Radius.circular(isSelected ? 20.0 : 0.0),
        ),
        color: isSelected ? AppColors.kWhite : AppColors.sideBarMenuColor,
      ),
      padding: const EdgeInsets.symmetric(vertical: 8.0),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          const SizedBox(width: 20.0),
          SvgPicture.asset(
            assetPath,
            width: 20.0,
            height: 20.0,
            color: AppColors.kSideMenuIconColor,
          ),
          if (_isHovered) ...[
            const SizedBox(width: 16.0),
            Expanded(
              child: Text(
                title,
                overflow: TextOverflow.ellipsis,
                style: TextStyle(
                  color: isSelected ? AppColors.kBlueColor : Colors.white,
                ),
                textAlign: TextAlign.left,
              ),
            ),
          ],
        ],
      ),
    ),
  );
}

问题

我已实现侧边栏菜单,但设计效果与参考示例不符。请问如何修改代码或调整实现思路,以达成示例中的设计效果?


解决方案

对比参考设计和你的实现,主要需要调整以下几点:

  1. 选中项视觉优化
    参考设计中选中项左侧有蓝色竖线,且白色背景从左侧边缘延伸到右侧圆角。修改_buildSidebarItem的BoxDecoration:

    decoration: BoxDecoration(
      borderRadius: BorderRadius.only(
        bottomRight: Radius.circular(20.0),
        topRight: Radius.circular(20.0),
      ),
      color: isSelected ? AppColors.kWhite : AppColors.sideBarMenuColor,
      border: isSelected ? Border(left: BorderSide(color: AppColors.kBlueColor, width: 4)) : null,
    ),
    

    同时把选中项的图标颜色改为蓝色:

    color: isSelected ? AppColors.kBlueColor : AppColors.kSideMenuIconColor,
    
  2. 菜单项布局调整
    参考设计的菜单项高度更高,调整容器padding增大垂直间距:

    padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 20.0),
    

    移除Row内的SizedBox(width:20.0),避免和容器水平padding重复。

  3. 文字过渡动画
    给文字添加淡入淡出效果,替换原文字部分代码:

    if (_isHovered) ...[
      const SizedBox(width: 16.0),
      Expanded(
        child: AnimatedOpacity(
          opacity: _isHovered ? 1.0 : 0.0,
          duration: const Duration(milliseconds: 200),
          child: Text(
            title,
            overflow: TextOverflow.ellipsis,
            style: TextStyle(
              color: isSelected ? AppColors.kBlueColor : Colors.white,
              fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal,
            ),
            textAlign: TextAlign.left,
          ),
        ),
      ),
    ],
    
  4. 单菜单项hover响应
    把MouseRegion移到每个菜单项内部,实现单独hover效果:
    先新增变量int _hoveredIndex = -1;,然后修改_buildSidebarItem:

    return MouseRegion(
      onEnter: (_) => setState(() => _hoveredIndex = index),
      onExit: (_) => setState(() => _hoveredIndex = -1),
      child: GestureDetector(
        onTap: () {
          setState(() {
            _selectedSidebarIndex = index;
          });
        },
        child: Container(
          decoration: BoxDecoration(
            borderRadius: BorderRadius.only(
              bottomRight: Radius.circular(20.0),
              topRight: Radius.circular(20.0),
            ),
            color: isSelected 
                ? AppColors.kWhite 
                : (_hoveredIndex == index ? AppColors.sideBarMenuHoverColor : AppColors.sideBarMenuColor),
            border: isSelected ? Border(left: BorderSide(color: AppColors.kBlueColor, width: 4)) : null,
          ),
          padding: const EdgeInsets.symmetric(vertical: 16.0, horizontal: 20.0),
          child: Row(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              SvgPicture.asset(
                assetPath,
                width: 20.0,
                height: 20.0,
                color: isSelected ? AppColors.kBlueColor : AppColors.kSideMenuIconColor,
              ),
              if (_isHovered || _hoveredIndex == index) ...[
                const SizedBox(width: 16.0),
                Expanded(
                  child: AnimatedOpacity(
                    opacity: (_isHovered || _hoveredIndex == index) ? 1.0 : 0.0,
                    duration: const Duration(milliseconds: 200),
                    child: Text(
                      title,
                      overflow: TextOverflow.ellipsis,
                      style: TextStyle(
                        color: isSelected ? AppColors.kBlueColor : Colors.white,
                        fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal,
                      ),
                      textAlign: TextAlign.left,
                    ),
                  ),
                ),
              ],
            ],
          ),
        ),
      ),
    );
    

    注意新增AppColors.sideBarMenuHoverColor作为hover时的背景色。

按上述调整后,即可贴近参考设计的外观与交互效果。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 05:13:13