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

Flutter自定义底部导航栏实现指导(含现有代码优化需求)

自定义底部导航栏实现指导

我想要创建一个自定义底部导航栏,样式要求如下:
目标样式:底部导航栏中间有一个突出的圆形图标,两侧各分布两个带文字标签的导航图标,选中的图标和文字有高亮效果,导航栏整体带有圆角缺口适配中间图标。

需要自定义应用中底部导航栏的外观与功能,恳请提供实现指导、技巧、代码片段或推荐资源。


补充说明

当前我的实现效果如下:
当前效果:底部导航栏有圆角缺口,中间放置了SVG图标但位置略有偏移,普通图标仅显示图标无文字标签,未实现选中态高亮。

以下是我当前的代码:

Widget build(BuildContext context) {
return Scaffold(
  appBar: AppBar(
    title: Text('Custom Bottom Navigation Bar'),
  ),
  body: Center(
    child: Text('Page ${_currentIndex + 1}'),
  ),
  bottomNavigationBar: Stack(
    children: <Widget>[
      BottomAppBar(
        shape: CircularNotchedRectangle(),
        child: Container(
          height: 60.0,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: <Widget>[
              IconButton(
                icon: Icon(Icons.home),
                onPressed: () {
                  setState(() {
                    _currentIndex = 0;
                  });
                },
              ),
              IconButton(
                icon: Icon(Icons.search),
                onPressed: () {
                  setState(() {
                    _currentIndex = 1;
                  });
                },
              ),
              SizedBox(width: 80.0), // 为SVG图标预留空间
              IconButton(
                icon: Icon(Icons.notifications),
                onPressed: () {
                  setState(() {
                    _currentIndex = 2;
                  });
                },
              ),
              IconButton(
                icon: Icon(Icons.person),
                onPressed: () {
                  setState(() {
                    _currentIndex = 3;
                  });
                },
              ),
            ],
          ),
        ),
      ),
      Positioned(
        top: -40.0,
        left: MediaQuery.of(context).size.width / 2 - 24.0,
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            SvgPicture.asset(
              'assets/rugby.svg', // 替换为你的SVG文件路径
              height: 80.0,
              width: 80.0,
            ),
            Text('Icône', style: TextStyle(fontSize: 12.0)),
          ],
        ),
      ),
    ],
  ),
);
}

优化实现方案

1. 匹配目标样式的核心调整

  • 选中态高亮:给选中的图标和文字添加颜色变化,底部增加高亮小色块标识
  • 中间图标优化:修正位置确保完全居中,添加点击事件,给图标套白色背景+阴影增强立体感
  • 文字标签补充:给底部普通导航图标添加对应文字标签,统一风格
  • 布局细节调整:调整导航栏高度,优化间距让整体更贴合目标样式

2. 优化后的完整代码

int _currentIndex = 0;

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: const Text('自定义底部导航栏'),
    ),
    body: Center(
      child: _getCurrentPage(),
    ),
    bottomNavigationBar: Stack(
      alignment: Alignment.center,
      children: <Widget>[
        BottomAppBar(
          elevation: 8,
          shape: const CircularNotchedRectangle(),
          color: Colors.white,
          child: SizedBox(
            height: 70,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: <Widget>[
                _buildNavItem(Icons.home, '首页', 0),
                _buildNavItem(Icons.search, '搜索', 1),
                const SizedBox(width: 80), // 为中间图标预留固定空间
                _buildNavItem(Icons.notifications, '通知', 2),
                _buildNavItem(Icons.person, '我的', 3),
              ],
            ),
          ),
        ),
        Positioned(
          top: -30,
          child: GestureDetector(
            onTap: () {
              setState(() {
                _currentIndex = 4; // 用特殊索引标识中间页面
              });
            },
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Container(
                  padding: const EdgeInsets.all(8),
                  decoration: BoxDecoration(
                    color: Colors.white,
                    borderRadius: BorderRadius.circular(40),
                    boxShadow: [
                      BoxShadow(
                        color: Colors.grey.withOpacity(0.3),
                        blurRadius: 8,
                        spreadRadius: 2,
                      )
                    ],
                  ),
                  child: SvgPicture.asset(
                    'assets/rugby.svg',
                    height: 60,
                    width: 60,
                  ),
                ),
                const SizedBox(height: 5),
                const Text('赛事', style: TextStyle(fontSize: 12)),
              ],
            ),
          ),
        ),
      ],
    ),
  );
}

// 封装导航项,统一处理选中/未选中状态
Widget _buildNavItem(IconData icon, String label, int index) {
  bool isSelected = _currentIndex == index;
  return GestureDetector(
    onTap: () {
      setState(() {
        _currentIndex = index;
      });
    },
    child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Icon(
          icon,
          color: isSelected ? Colors.blue : Colors.grey,
          size: 26,
        ),
        const SizedBox(height: 4),
        Text(
          label,
          style: TextStyle(
            color: isSelected ? Colors.blue : Colors.grey,
            fontSize: 12,
            fontWeight: isSelected ? FontWeight.w500 : FontWeight.normal,
          ),
        ),
        if (isSelected)
          Container(
            width: 20,
            height: 2,
            color: Colors.blue,
            margin: const EdgeInsets.only(top: 2),
          ),
      ],
    ),
  );
}

// 根据当前索引返回对应页面
Widget _getCurrentPage() {
  switch (_currentIndex) {
    case 0:
      return const Text('首页');
    case 1:
      return const Text('搜索页');
    case 2:
      return const Text('通知页');
    case 3:
      return const Text('个人中心');
    case 4:
      return const Text('赛事页面');
    default:
      return const Text('首页');
  }
}

3. 关键实现技巧

  • 组件封装:用_buildNavItem方法统一处理导航项的状态,减少重复代码,便于后续样式修改
  • 立体效果:给中间图标添加白色背景和阴影,模拟悬浮突出的视觉效果
  • 精准布局:通过Stack的alignment: Alignment.center直接让中间图标居中,避免手动计算屏幕宽度的误差
  • 状态扩展:如果应用复杂度较高,可替换setState为Provider、GetX等状态管理工具,提升性能和可维护性
  • 交互完善:给所有导航项添加点击事件,中间图标单独处理跳转逻辑,确保功能完整

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 13:09:55