Files
tuiche/lib/pages/common/bezier_bottom_navigation_bar.dart
2025-06-03 09:34:31 +08:00

152 lines
4.4 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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<int> onTap;
final List<String> path;
final List<String> 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;
}
}