import 'dart:math' as math; import 'package:flutter/cupertino.dart'; class DashedProgressPainter extends CustomPainter { final double progress; // 0..1 final double thickness; final double dash; final double gap; final Color baseColor; final Color progressColor; final double radius; DashedProgressPainter({ required this.progress, required this.thickness, required this.dash, required this.gap, required this.baseColor, required this.progressColor, required this.radius, }); @override void paint(Canvas canvas, Size size) { final y = size.height / 2; final dashPaintBase = Paint()..color = baseColor..style = PaintingStyle.fill; final dashPaintProg = Paint()..color = progressColor..style = PaintingStyle.fill; final total = size.width; final cutoff = total * progress; // everything left of this is colored double x = 0; while (x < total) { final dashEnd = (x + dash).clamp(0.0, total); final rrect = RRect.fromRectAndRadius( Rect.fromLTWH(x, y - thickness / 2, dashEnd - x, thickness), Radius.circular(radius), ); // base (grey) dash canvas.drawRRect(rrect, dashPaintBase); // overlap the colored part inside this dash (if any) final colorEnd = math.min(dashEnd, cutoff); if (colorEnd > x) { final coloredRect = RRect.fromRectAndRadius( Rect.fromLTWH(x, y - thickness / 2, colorEnd - x, thickness), Radius.circular(radius), ); canvas.drawRRect(coloredRect, dashPaintProg); } x += dash + gap; } } @override bool shouldRepaint(covariant DashedProgressPainter old) { return old.progress != progress || old.thickness != thickness || old.dash != dash || old.gap != gap || old.baseColor != baseColor || old.progressColor != progressColor || old.radius != radius; } }