I am wondering why and when you would use Canvas.save
, Canvas.restore
, and maybe even Canvas.saveLayer
.
I have heard that they are really useful, but I do not know when to use them.
It removes the change in settings, but not the drawing itself. Settings can include scaling the canvas etc., and it restores the scaling to the initial state when you called canvas.
The CanvasRenderingContext2D. save() method of the Canvas 2D API saves the entire state of the canvas by pushing the current state onto a stack.
Canvas.save
and Canvas.saveLayer
work slightly differently, but they both have the same counterpart:
Canvas.restore
This allows you to restore the state before the most recent entry on the save stack, i.e. it "Pops the current save stack". This means that any transformations and clips done to the canvas in the current state will be removed and if saveLayer
was used, the saved layer will be composited into the canvas (the draw order will remain the same).
Canvas.save
As I mentioned earlier, this allows you to save the state the canvas is in. You can do any transformation and clips you want and those will be removed using restore
:
canvas.save();
canvas.transform(..); // Transforms the canvas, which will affect the draw call.
canvas.drawRect(...); // Affected by the transform.
canvas.restore();
canvas.drawRect(...); // Not affected by the transform.
You can use any number of save
before restore
and the stack will remember all entries, i.e. restore
will always pop the most recent entry.
Example: if you wanted to rotate a single piece when drawing a bigger picture, you can simply do the rotation inside a save
-restore
block and draw something without the rotation on top afterwards.
Note that all children of a RenderObject
will use the same PaintingContext
, i.e. the same Canvas
. So if you transform the canvas in a single child, it will also be transformed for all other children that draw afterwards. This is potentially unwanted behavior and the reason why you always want to save
and restore
the canvas state.
Canvas.saveLayer
This is a bit more complicated and I urge you to read the comprehensive documentation of this method. Btw, saveLayer
does not work in Flutter web as of January, 2019.
The basic difference between saveLayer
and save
is that saveLayer
will composite the layer upon usage of restore
. For a simple example, I constructed this snippet without bounds
(which is why null
is passed), which will save the whole canvas:
canvas.drawRect(rect, Paint()..color = const Color(0xffff0000)); // Draws a red rect.
canvas.saveLayer(null, Paint()..blendMode = BlendMode.multiply); // Saves the whole canvas.
canvas.drawRect(
rect.shift(const Offset(20, 20)),
Paint()..color = const Color(0xff0000ff), // Draws a blue rect.
);
canvas.restore(); // Composites the red rect into the blue rect.
Note that the blue rect will still be composited above the red rect.
This example could also be achieved without using saveLayer
because the Paint.blendMode
I used can also be passed to Canvas.drawRect
. However, when using e.g. a TextPainter
, you cannot pass blend modes. Additionally, saveLayer
allows you to pass bounds, which gives far more possibilites (read the documentation for more information, also about clips). Clipping is actually probably the most useful operation in combination with saveLayer
- I did not include it in order to have a simple example.
This is how the example would look without saveLayer
:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With