1

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).

AlienKevin
  • 2,691
  • 2
  • 17
  • 19
  • 2
    https://pub.dev/documentation/path_drawing/latest/path_drawing/dashPath.html - all you need to do is to call `moveTo` and `lineTo` on your `Path` - it should be faster than multiple calls to `Canvas.drawLine` – pskink Dec 25 '22 at 07:07
  • @pskink Thanks for pointing out the path_drawing library and the path commands. Since I'm only drawing a few dashed lines, I think the overhead of drawLine is not very pronounced. If you are interested, feel free to edit my answer to use path commands or provide your own alternative. – AlienKevin Dec 25 '22 at 16:37

1 Answers1

2

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]

pskink
  • 23,874
  • 6
  • 66
  • 77
AlienKevin
  • 2,691
  • 2
  • 17
  • 19
  • 1
    your code does not draw the last segment correctly, see the updated method - try: `final p1 = Offset(100, 100); final p2 = Offset(300, 200); drawDashedLine(canvas: canvas, p1: p1, p2: p2, dashWidth: 20, dashSpace: 10, paint: p);` with your and my version and you will notice the difference on the last drawn segment, you can add `canvas.drawCircle(p2, 8, paint)` to better "see" the line end point – pskink Dec 25 '22 at 18:11
  • @pskink Your upated method looks fantastic. I wasn't aware of such functions like `Offset.lerp` and `Offset.distance` so I did the component math by hand. – AlienKevin Dec 28 '22 at 15:53
  • 1
    indeed, a little bit like reinventing the wheel, now life is simpler :-) – pskink Dec 28 '22 at 16:02
  • btw `lerp` method is very handy and is used in many classes like `Rect.lerp`, `Size.lerp`, `Alignment.lerp`, `Color.lerp` and more than 100 other classes – pskink Dec 28 '22 at 17:25