Flutter 椭圆弧型(弓型)进度条

首先我们定义一个椭圆弧型进度条组件。

/// 圆弧进度条
class CurveProgressIndicator extends StatelessWidget {
  const CurveProgressIndicator({
    super.key,
    this.size = Size.zero,
    required this.progress,
  });

  /// 监听器
  final ValueNotifier<double> progress;

  /// 尺寸
  final Size size;

  @override
  Widget build(BuildContext context) {
    debugPrint("重绘:底部进度条");
    return RepaintBoundary(
      child: CustomPaint(
        size: size,
        painter: CurveProgressIndicatorPainter(progress),
      ),
    );
  }
}

接着我们定义一个自定义画刷。

/// 圆弧进度条的绘制器
class CurveProgressIndicatorPainter extends CustomPainter {
  const CurveProgressIndicatorPainter(this.progress) : super(repaint: progress);

  /// 监听器
  final ValueNotifier<double> progress;

  @override
  void paint(Canvas canvas, Size size) {
    if (progress.value == 0) {
      //没有进度不绘制
      return;
    }
    debugPrint("重绘:底部进度条-画刷");

    // 贝塞尔曲率
    double bezier = size.height / 4;

    // 绘制弧线
    Path line = Path()
      ..moveTo(0, bezier)
      ..quadraticBezierTo(size.width / 2, -bezier, size.width, bezier);

    // 定义画刷
    var gradient = Gradient.linear(
      Offset.zero,
      Offset(size.width, 0),
      [
        const Color(0xFFB7EAFF),
        const Color(0xFF7ED9FF),
        const Color(0xFF0F7BAA),
        // Colors.red, Colors.blue, Colors.yellow,
      ],
      [0, 0.6, 1],
    );

    // 绘制扇形进度条
    var paint = Paint()
      //..color = progressColor
      ..shader = gradient
      ..strokeWidth = 2.5
      ..strokeCap = StrokeCap.round
      ..style = PaintingStyle.stroke;

    //计算百分比进度条
    PathMetrics pathMetrics = line.computeMetrics();
    // 获取第一小节信息(猜测可能有多个Path叠加?)
    PathMetric pathMetric = pathMetrics.first;
    // 整个Path的长度
    double length = pathMetric.length;
    // 当前进度
    double value = length * progress.value;
    Path extractPath = pathMetric.extractPath(0, value, startWithMoveTo: true);
    canvas.drawPath(extractPath, paint);
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }
}

详细解析

弧线的路径定义:

定义一个高度为Size容器 4分之1的高度 (我这里是将Size设置成100,因为我的案例中播放器底部有一个圆弧形的背景, 可以根据实际情况设置参数),

将起点放置于(0,bezier),绘制弧线点(x1,y1) = (宽度/2,-bezier) ,(x2,y3) = (宽度,bezier)。

关于百分比进度的绘制方法:

需要根据PathMetrics获取到line的总长度,再通过 double value = length * progress.value 计算出当前的路径,最后绘制 渐变色 就完成了。

//计算百分比进度条
    PathMetrics pathMetrics = line.computeMetrics();
    // 获取第一小节信息(猜测可能有多个Path叠加?)
    PathMetric pathMetric = pathMetrics.first;
    // 整个Path的长度
    double length = pathMetric.length;
    // 当前进度
    double value = length * progress.value;
    Path extractPath = pathMetric.extractPath(0, value, startWithMoveTo: true);
    canvas.drawPath(extractPath, paint);

看看成品:

扫描二维码关注公众号,回复: 17516234 查看本文章

原文链接:https://juejin.cn/post/7433605370653720588

猜你喜欢

转载自blog.csdn.net/qq_66118130/article/details/143576876