// bezier_bottom_navigation_bar.dart import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:vbvs_app/common/util/FitTool.dart'; class BezierBottomNavigationBar extends StatelessWidget { final int selectedIndex; final double animatedPosition; final ValueChanged onTap; final List path; final List titles; const BezierBottomNavigationBar({ Key? key, required this.selectedIndex, required this.animatedPosition, required this.onTap, required this.path, required this.titles, }) : super(key: key); @override Widget build(BuildContext context) { final itemCount = path.length; return SizedBox( height: 130.rpx, child: Stack( children: [ Positioned.fill( child: CustomPaint( size: Size(MediaQuery.of(context).size.width, 130.rpx), painter: BezierPainter( position: animatedPosition, itemCount: itemCount, ), ), ), Row( children: path.asMap().entries.map((entry) { final i = entry.key; final icon = entry.value; return Expanded( child: GestureDetector( // 用 InkWell 替换 GestureDetector,支持点击反馈 onTap: () => onTap(i), // splashColor: Colors.transparent, // 可选:关闭 splash 效果 // highlightColor: Colors.transparent, // 可选:关闭高亮效果 child: SizedBox.expand( child: Padding( padding: EdgeInsets.only(top: 14.rpx), child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ Padding( padding: EdgeInsets.only(top: 11.rpx), child: SvgPicture.asset(icon, width: 42.rpx, height: 42.rpx, color: selectedIndex == i ? Colors.white : Color(0XFF929699)), ), SizedBox(height: 3), Text( titles[i], style: TextStyle( fontSize: 22.rpx, color: selectedIndex == i ? Colors.white : Colors.grey.shade400, ), ), ], ), ) // 关键点:撑满 Expanded 区域 ), ), ); }).toList(), ), ], ), ); } } class BezierPainter extends CustomPainter { final double position; final int itemCount; BezierPainter({required this.position, required this.itemCount}); @override void paint(Canvas canvas, Size size) { final paint = Paint() ..color = Colors.white ..style = PaintingStyle.stroke ..strokeWidth = 1.0; final path = Path(); final itemWidth = size.width / itemCount; final curveWidth = itemWidth * 0.8; double curveHeight = 8.5; final centerX = itemWidth * position + itemWidth / 2; final left = centerX - curveWidth / 2; final right = centerX + curveWidth / 2; // 控制点偏移比例(越小越平滑) final controlOffsetX = curveWidth * 0.2; final controlOffsetY = curveHeight * 0.9; // 起点 path.moveTo(0, 0); // 到左侧前的一段直线 path.lineTo(left, 0); // 凸起贝塞尔曲线 path.cubicTo( left + controlOffsetX, 0, centerX - controlOffsetX, -controlOffsetY, centerX, -controlOffsetY, ); path.cubicTo( centerX + controlOffsetX, -controlOffsetY, right - controlOffsetX, 0, right, 0, ); // 右边剩余直线 path.lineTo(size.width, 0); // 向下平移,保证凸起在容器内部 canvas.translate(0, controlOffsetY); canvas.drawPath(path, paint); } @override bool shouldRepaint(covariant BezierPainter oldDelegate) { return oldDelegate.position != position; } }