Reputation: 1515
Is it possible to draw a line in Flutter with a complete custom pattern that repeats itself along the line? For example, I want to have this pattern:
So if I draw a straight line, it should like like this:
Now, I don't just want to draw straight lines. I actually want to draw polylines on a map. I am using the flutter_map
package. I saw that the PolylineLayer
Widget just uses a CustomPainter
to draw the lines along the map. The Polilines are not very customizable (they just come with options for a border, dashes, etc). So my idea is to just create another widget that does exactly the same as the PolylineLayer
widget, but with my own CustomPainter, that should draw the custom pattern along the path. Ideally I could just create an svg with the pattern and apply it to the path, if that is possible.
Edit
I tried pskink
s Answer. It generally works, but it doesn't quite work for a curved line. Here is my code:
@override
void paint(Canvas canvas, Size size) {
var path = ui.Path();
final paint = Paint()
..strokeWidth = polyline.strokeWidth
..strokeCap = polyline.strokeCap
..strokeJoin = polyline.strokeJoin
..style = PaintingStyle.stroke
..shader = ImageShader(
polyline.image, // this is a ui.Image
TileMode.repeated,
TileMode.repeated,
Matrix4.identity().storage,
);
final offsets = getOffsets(polyline.points);
_paintLine(path, offsets);
canvas.drawPath(path, paint);
}
void _paintLine(ui.Path path, List<Offset> offsets) {
if (offsets.isEmpty) {
return;
}
path.addPolygon(offsets, false);
}
List<Offset> getOffsets(List<LatLng> points) {
// Calculate offsets on map
}
Now, the line is drawn, the path is correct, and the line has the pattern of the image. But the direction of the image doesn't follow the line.
The image that I use for the pattern looks like this:
The outcome I expect should look somewhat like this. This is just an example to visualize that the image direction should follow the line. It should be even more curved in reality:
The current outcome looks somewhat like this. I hope it makes the problem clear. The direction does not follow the line:
This is what it actually looks like in my app (to visualize it again):
Edit 2
I to draw each line individually with composeMatrix as mentioned by pskink
. The patterns get rotated, but I can't seem to figure out the strokeWidth and translation. The height of my image should stretch exactly across the height of the line. The width of my image should not stretch, instead it should repeat. Here is my code, and below is the current outcome.
@override
void paint(Canvas canvas, Size size) {
for (final polyline in polylines) {
final offsets = getOffsets(polyline.points);
if (offsets.isEmpty) {
continue;
}
final image = _cacheManager.getImageSync(polyline.svgPath);
final paint = Paint()
..strokeWidth = polyline.strokeWidth
..strokeCap = polyline.strokeCap
..strokeJoin = polyline.strokeJoin
..style = PaintingStyle.stroke;
for (int i = 0; i < offsets.length - 1; i++) {
final p1 = offsets[i];
final p2 = offsets[i + 1];
final angle = (p2 - p1).direction;
final center = Offset((p1.dx + p2.dx) / 2, (p1.dy + p2.dy) / 2);
final matrix = composeMatrix(
anchor: center,
rotation: angle,
scale: polyline.strokeWidth / image.height,
translate: p1,
);
final shader = ImageShader(
image,
TileMode.repeated,
TileMode.repeated,
matrix.storage,
);
paint.shader = shader;
final path = ui.Path()
..moveTo(p1.dx, p1.dy)
..lineTo(p2.dx, p2.dy);
canvas.drawPath(path, paint);
}
}
}
@override
bool shouldRepaint(covariant SvgPolylinePainter oldDelegate) {
return oldDelegate.bounds != bounds ||
oldDelegate.polylines.length != polylines.length ||
oldDelegate.hash != hash;
}
}
Upvotes: 0
Views: 260