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

如何在Flutter的BottomNavigationBar中心图标上方添加凹口?

给Flutter BottomNavigationBar中心图标上方添加凹口的实现方案

可以实现你要的凹口效果,默认的BottomNavigationBar组件本身不支持直接添加这种凹口,不过我们可以通过Stack + 自定义裁剪背景的方式来实现,下面是具体的实现代码和思路:

实现思路

  1. 用Stack组件将自定义的带凹口底部背景、透明化的BottomNavigationBar,以及悬浮的中心图标组合在一起
  2. 将BottomNavigationBar的中间项设为空白占位,避免和悬浮图标冲突
  3. 通过CustomClipper绘制带凹口的底部背景,控制凹口的大小和深度

完整代码示例

替换你原来的BottomNavigationBar代码为以下实现:

return Stack(
  alignment: Alignment.bottomCenter,
  children: [
    // 带凹口的底部背景容器
    ClipPath(
      clipper: BottomNavNotchClipper(),
      child: Container(
        height: kBottomNavigationBarHeight,
        color: Colors.white, // 这里设置底部导航栏的背景色
      ),
    ),
    // 透明化的底部导航栏
    BottomNavigationBar(
      type: BottomNavigationBarType.fixed,
      fixedColor: Color(0xff2398C3),
      showSelectedLabels: false,
      showUnselectedLabels: false,
      currentIndex: snapshot.data.index,
      onTap: _bottomNavBarBloc.pickItem,
      backgroundColor: Colors.transparent, // 设为透明,显示下方的凹口背景
      elevation: 0, // 移除导航栏阴影
      items: [
        BottomNavigationBarItem(
          label: 'Search',
          icon: Icon(Icons.search),
        ),
        BottomNavigationBarItem(
          label: 'Browse',
          icon: Icon(Icons.view_list),
        ),
        BottomNavigationBarItem(
          label: 'Icon',
          icon: SizedBox.shrink(), // 中间项设为空白占位
        ),
        BottomNavigationBarItem(
          label: 'Favorites',
          icon: Icon(Icons.bookmark),
        ),
        BottomNavigationBarItem(
          label: 'Settings',
          icon: Icon(Icons.settings),
        ),
      ],
    ),
    // 悬浮在凹口处的中心图标
    Positioned(
      bottom: kBottomNavigationBarHeight / 2 - 17.5, // 调整位置让图标居中悬浮
      child: GestureDetector(
        onTap: () => _bottomNavBarBloc.pickItem(2), // 绑定导航栏中间项的点击事件
        child: Container(
          child: FlutterLogo(
            size: 35.0,
          ),
        ),
      ),
    ),
  ],
);

// 自定义裁剪器,用于绘制底部导航栏的凹口
class BottomNavNotchClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    final path = Path();
    final notchWidth = 60.0; // 凹口的宽度
    final notchDepth = 15.0; // 凹口的深度

    // 从左下角开始绘制路径
    path.moveTo(0, 0);
    // 绘制到凹口左侧位置
    path.lineTo((size.width - notchWidth) / 2, 0);
    // 绘制凹口左半部分的弧线
    path.quadraticBezierTo(
      (size.width - notchWidth) / 2,
      -notchDepth,
      size.width / 2,
      -notchDepth,
    );
    // 绘制凹口右半部分的弧线
    path.quadraticBezierTo(
      (size.width + notchWidth) / 2,
      -notchDepth,
      (size.width + notchWidth) / 2,
      0,
    );
    // 绘制到右下角,再闭合路径
    path.lineTo(size.width, 0);
    path.lineTo(size.width, size.height);
    path.lineTo(0, size.height);
    path.close();
    return path;
  }

  @override
  bool shouldReclip(covariant CustomClipper<Path> oldClipper) => false;
}

关键细节说明

  • 你可以通过修改BottomNavNotchClipper里的notchWidth和notchDepth参数,调整凹口的宽度和深度,匹配你的设计需求
  • 悬浮图标的位置通过Positioned的bottom属性调整,确保刚好卡在凹口处
  • 将BottomNavigationBar的backgroundColor设为透明、elevation设为0,是为了让下方的凹口背景完全显示出来

内容的提问来源于stack exchange,提问作者Md Shamim Hossain

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 12:03:20