Efficient Canvas rendering in Flutter
This is the Controller class
class DrawingController extends ChangeNotifier {
List<Offset> _points = []
.... // Perform operations on data points
....
void add(Offset point) {
_points.add(point);
notifyListeners();
}
}
This is the CustomPaint
class
class Painter extends CustomPainter {
DrawingController controller;
Painter(this.controller) : super(repaint: controller); //This is important
@override
void paint(Canvas canvas, Size size) {
//Paint function
}
@override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
And in the Gesture detector simply call controller.add(point)
to add new points as you grab them
I am not sure this is the most efficient way to paint but it reduced the paint times down to 13ms on a 60hz screen and 9ms on a 120Hz screen. One noticeable drawback is that a single stroke (onTapdownEvent to an onDragEndEvent) renders quite slowly(up to 18ms) when the stroke has many points. This problem disappears as soon as you start a new stroke. I tried asking on several forums and this is the best I could come up with after digging through the flutter source code.
I profiled this functionality on a snapdragon 855 device so the processor is not a bottleneck. If anyone finds a better solution please post it.
Dhruva
Updated on November 28, 2022Comments
-
Dhruva over 1 year
I have been trying to develop a drawing app and all the example codes including the one's from The Boring Flutter Development Show don't translate well into real-world usage.
The main problem being that
CustomPaint
's paint operation is too expensive and re-draws every point, every frame. And as the points increase the flutter app's render time per frame increases significantlyFrom the time I spent finding a solution to this problem, I found these
RepaintBoundary
: Rasterizes layersCustom Widget using
SingleChildRenderObjectWidget
andRenderProxyBox
: must implement a paint method and no way of passing a controller
I don't think any of the above solutions work well for my needs: smooth canvas drawing operations without re-paint. I even tried simplifying the points and that didn't work either because of the inherent mechanism of
CustomPaint
If there was a way to pass a canvas as a widget and attaching a controller it'll be easy to store the captured points and use basic canvas operations like
canvas.drawPath()
orcanvas.drawLine()
much efficientlyAny suggestion would be helpful. Thank you!
-
pskink almost 4 years
PictureRecorder
maybe? -
Dhruva almost 4 years@pskink from all the examples I have seen, I couldn't find any example which passed around either PictureRecorder or Canvas as a Widget where you can render real-time touch events. I apologise if I sounded naive as I started learning flutter recently.
-
Alex over 3 years@Dhruva have you found a solution?
-
Dhruva over 3 years@Alex I will post an answer