How to draw a dashed line in a CustomPainter in Flutter?

2.6k Views Asked by At

There's no native API for drawing a dashed line in Flutter. An existing snippet allows drawing horizontal dashed lines but I can't find a snippet for drawing arbitrary dashed line from one point to another. There also exists a library called dash_painter that draws a dashed path. However, I'm only interested in drawing simple dashed lines. In particular, I'm looking for a snippet for drawing dashed lines that's similar to canvas.drawLine(Offset p1, Offset p2, Paint paint).

1

There are 1 best solutions below

4
On

Here's a function for drawing a dashed line from point p1 to point p2 in a CustomPainter:

void drawDashedLine(
      {required Canvas canvas,
      required Offset p1,
      required Offset p2,
      required int dashWidth,
      required int dashSpace,
      required Paint paint}) {
  // Get normalized distance vector from p1 to p2
  var dx = p2.dx - p1.dx;
  var dy = p2.dy - p1.dy;
  final magnitude = sqrt(dx * dx + dy * dy);
  dx = dx / magnitude;
  dy = dy / magnitude;

  // Compute number of dash segments
  final steps = magnitude ~/ (dashWidth + dashSpace);

  var startX = p1.dx;
  var startY = p1.dy;

  for (int i = 0; i < steps; i++) {
    final endX = startX + dx * dashWidth;
    final endY = startY + dy * dashWidth;
    canvas.drawLine(Offset(startX, startY), Offset(endX, endY), paint);
    startX += dx * (dashWidth + dashSpace);
    startY += dy * (dashWidth + dashSpace);
  }
}

Example usage: Draw a red dashed line from (0, 0) to (100, 100) with dash width of 6 and spacing of 4.

drawDashedLine(
    canvas: canvas,
    start: Offset(0, 0),
    end: Offset(100, 100),
    dashWidth: 6,
    dashSpace: 4,
    paint: Paint()..color = Colors.red..strokeWidth = 1);

EDIT

this is a version that uses one Canvas.drawPoints method call:

void drawDashedLine({
  required Canvas canvas,
  required Offset p1,
  required Offset p2,
  required Iterable<double> pattern,
  required Paint paint,
}) {
  assert(pattern.length.isEven);
  final distance = (p2 - p1).distance;
  final normalizedPattern = pattern.map((width) => width / distance).toList();
  final points = <Offset>[];
  double t = 0;
  int i = 0;
  while (t < 1) {
    points.add(Offset.lerp(p1, p2, t)!);
    t += normalizedPattern[i++];  // dashWidth
    points.add(Offset.lerp(p1, p2, t.clamp(0, 1))!);
    t += normalizedPattern[i++];  // dashSpace
    i %= normalizedPattern.length;
  }
  canvas.drawPoints(ui.PointMode.lines, points, paint);
}

in the most simple form you can call it with pattern: [20, 10] but more complex patterns are possible: pattern: [20, 5, 5, 5]