如何在Flutter中实现底部导航栏的曲线效果?
Flutter 带曲线效果的底部导航栏实现方案
下面给你两种适配需求的实现方式,都是基于原生组件扩展,不用依赖第三方包:
方法一:全局曲线裁剪的底部导航栏
适合整个导航栏底部带曲线的场景,用ClipPath自定义裁剪路径即可:
- 先写一个自定义裁剪器,定义曲线形状:
class CurveBottomClipper extends CustomClipper<Path> { @override Path getClip(Size size) { final path = Path(); // 从左下角开始绘制路径 path.lineTo(0, size.height); // 左侧直线到曲线起点 path.lineTo(size.width * 0.3, size.height); // 绘制中间向上凸起的贝塞尔曲线 path.quadraticBezierTo( size.width * 0.5, // 曲线控制点X size.height - 30, // 曲线控制点Y(数值越大,凸起越高) size.width * 0.7, // 曲线终点X size.height, // 曲线终点Y ); // 右侧直线到右下角 path.lineTo(size.width, size.height); path.lineTo(size.width, 0); return path; } @override bool shouldReclip(CustomClipper<Path> oldClipper) => false; }
- 把底部导航栏套在
ClipPath里使用:
ClipPath( clipper: CurveBottomClipper(), child: Container( height: 60, color: Colors.white, child: BottomNavigationBar( elevation: 0, // 去掉默认阴影,避免和曲线冲突 backgroundColor: Colors.transparent, items: const [ BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'), BottomNavigationBarItem(icon: Icon(Icons.search), label: '搜索'), BottomNavigationBarItem(icon: Icon(Icons.person), label: '我的'), ], ), ), )
方法二:选中项凸起的曲线导航栏
如果是指定某个Tab(比如中间的发布按钮)有单独的凸起曲线,用Stack叠加层来实现:
- 自定义绘制曲线的Painter:
class CurvePainter extends CustomPainter { @override void paint(Canvas canvas, Size size) { final paint = Paint()..color = Colors.blue; // 曲线颜色和导航栏区分开 final path = Path(); // 绘制向上凸起的圆弧曲线 path.moveTo(0, 0); path.quadraticBezierTo( size.width / 2, -20, // 凸起高度,负数表示向上凸 size.width, 0, ); // 闭合路径,形成一个带曲线的色块 path.lineTo(size.width, size.height); path.lineTo(0, size.height); path.close(); canvas.drawPath(path, paint); } @override bool shouldRepaint(CustomPainter oldDelegate) => false; }
- 用Stack组合导航栏、背景和曲线:
int _selectedIndex = 1; // 默认选中中间项 Stack( alignment: Alignment.bottomCenter, children: [ // 导航栏基础背景 Container( height: 60, color: Colors.white, ), // 选中项的曲线装饰,根据选中位置动态调整 Positioned( bottom: 0, left: MediaQuery.of(context).size.width / 2 - 40, // 居中放置,宽度80 child: CustomPaint( size: const Size(80, 30), painter: CurvePainter(), ), ), // 底部导航栏,背景设为透明 BottomNavigationBar( elevation: 0, backgroundColor: Colors.transparent, currentIndex: _selectedIndex, onTap: (index) { setState(() { _selectedIndex = index; }); }, items: const [ BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'), BottomNavigationBarItem(icon: Icon(Icons.add_circle), label: '发布'), BottomNavigationBarItem(icon: Icon(Icons.person), label: '我的'), ], ), ], )
调整技巧
- 曲线弧度:修改
quadraticBezierTo的控制点坐标,就能调整曲线的弯曲程度和凸起高度。 - 适配屏幕:尽量用比例值(比如
size.width * 0.5)代替固定像素,避免不同屏幕上变形。 - 阴影效果:可以给曲线容器加
BoxShadow,或者在CustomPaint里多画一层灰色的阴影路径,增强立体感。
内容的提问来源于stack exchange,提问作者Tarek mohamed Hassain
相关产品推荐
相关产品推荐

