首先我们定义一个椭圆弧型进度条组件。
/// 圆弧进度条 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