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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 20:35:39