Flutter弧形进度条实现问询及已尝试代码分享
弧形进度条实现方案
现有代码的核心问题
你提供的代码思路是对的,但有两个关键问题导致进度条无法正常工作:
shouldRepaint固定返回false,进度值变化时不会触发重绘- 未对裁剪百分比做范围限制,极端值可能导致绘制异常
修正后的完整实现
class ShapePainter extends CustomPainter { final double value; final double total; ShapePainter({required this.value, required this.total}); @override void paint(Canvas canvas, Size size) { const backgroundColor = Color(0xFFFFEEE9); const activeColor = Color(0xFFFF8875); final backgroundPaint = createPaint(backgroundColor); final activePaint = createPaint(activeColor); final startPoint = Offset(0, size.height / 2); final endPoint = Offset(size.width, size.height / 2); // 调整控制点可以改变弧形的弯曲幅度 final controlPoint1 = Offset(size.width / 4, size.height); final controlPoint2 = Offset(3 * size.width / 4, size.height); final path = Path() ..moveTo(startPoint.dx, startPoint.dy) ..cubicTo( controlPoint1.dx, controlPoint1.dy, controlPoint2.dx, controlPoint2.dy, endPoint.dx, endPoint.dy, ); // 绘制背景弧形 canvas.drawPath(path, backgroundPaint); // 裁剪出对应进度的激活路径 final trimmedPath = trimPath(path, value / total); canvas.drawPath(trimmedPath, activePaint); } Paint createPaint(Color color) { return Paint() ..color = color ..strokeWidth = 5 ..style = PaintingStyle.stroke ..strokeCap = StrokeCap.round; } Path trimPath(Path source, double percentage) { final dest = Path(); // 限制百分比在0-1之间,避免越界 final validPercent = percentage.clamp(0.0, 1.0); for (final metric in source.computeMetrics()) { dest.addPath( metric.extractPath(0.0, metric.length * validPercent), Offset.zero, ); } return dest; } @override bool shouldRepaint(ShapePainter oldDelegate) { // 进度值或总量变化时重绘 return oldDelegate.value != value || oldDelegate.total != total; } }
关键优化点
- 重绘触发逻辑:
shouldRepaint对比新旧实例的value和total,确保进度更新时界面实时刷新 - 参数安全处理:用
clamp限制裁剪百分比范围,避免因超出0-1导致的绘制错误 - 代码简洁性:使用级联操作简化路径创建代码
调用示例
将进度条集成到Widget中:
class ArcProgressWidget extends StatelessWidget { final double currentProgress; final double maxProgress; const ArcProgressWidget({ super.key, required this.currentProgress, required this.maxProgress, }); @override Widget build(BuildContext context) { return CustomPaint( size: const Size(320, 120), // 根据布局需求调整尺寸 painter: ShapePainter(value: currentProgress, total: maxProgress), ); } }
这样就能实现你想要的向下弯曲的弧形进度条,进度变化时激活段会从左到右逐步延伸。
内容的提问来源于stack exchange,提问作者Kevin Louis
相关产品推荐
相关产品推荐

