56

I often see the following code

canvas.save().
canvas translate or rotate
some drawing
canvas.restore

I don't understand why we save and then restore. What's the point of undoing what we just did! I am sure I am missing something here Thanks

Snake
  • 14,228
  • 27
  • 117
  • 250
  • if you qre not quite sure what docs say, try to experiment a bit with those methods and see what they actually do – pskink Mar 13 '15 at 19:19
  • related : http://stackoverflow.com/questions/3051981/why-do-we-use-canvas-save-or-canvas-restore – petey Jan 06 '17 at 18:07
  • for more understand, refer to this artical: https://stackoverflow.com/questions/5789813/what-does-canvas-translate-do – Huy Nguyen Apr 08 '18 at 15:40
  • for more understand, refer to this article: https://stackoverflow.com/questions/5789813/what-does-canvas-translate-do – Huy Nguyen Apr 08 '18 at 17:16

5 Answers5

124

I understand this question is a bit dated, but for anyone still looking for an answer I can ELI5;

Imagine the canvas is a piece of paper, and you're tasked with drawing a picture of a robot right side up, at the bottom, and another robot upside down, slightly moved to the right, and about 40% smaller at the top. Something like this; Android canvas example

How would you start? What's easier to do first?

You would probably draw the bigger robot at the bottom first since it's right-side up and it's a lot easier to draw in the direction that feels more natural. So you've got the first one done, now how do you approach the second upside down robot?

  • You could attempt to draw it as is, but that would be a bit difficult since you're upside down.

or

  • You could rotate your paper 180°, move your starting point a bit, and start drawing at a smaller scale, and after you're all done you'd just rotate the paper back.

This is what canvas.save() and canvas.restore() do, they allow you to modify your canvas in any way that makes it easier for you to draw what you need. You don't need to use these methods, but they sure do simplify a lot of the process. The above would look something like

drawRobot()
canvas.save()
canvas.rotate(180)
canvas.translate(100, 0)
canvas.scale(40,40)
drawRobot()
canvas.restore()

If we look at the restore() documentation it says

is used to remove all modifications to the matrix/clip state since the last save call

and to see what those modifications are we take a look at save() it says

translate, scale, rotate, skew, concat or clipRect, clipPath

Well look at that, we did in fact use translate rotate and scale but we also did call drawRobot() so wouldn't calling restore erase our drawing? No, because it doesn't affect the drawing, only the modifications. So when we call restore it will return our canvas to the state that it was in before we started the second drawing.

Pztar
  • 4,274
  • 6
  • 33
  • 39
33

What's the point of undoing what we just did!

You're not, though. If you're just going off the words, it does sound like that's what might happen, but it actually isn't.

Think of it like this:

You have a series of really complex translations and rotations you want to apply in the same onDraw(Canvas) call. Now, since every translation/rotation you apply to the Canvas happens in order, you would have to undo your last adjustments to the Canvas, or somehow calculate your new adjustments based off the previous one before drawing whatever it is you want to draw. That would get very messy, very quickly.

Using canvas.save() and canvas.restore() is a ridiculously easy way to simplify that process.

By doing adjustments that apply to the Canvas within a save/restore block, you're effectively isolating said adjustments so that whatever you want to draw next won't be affected by what you're drawing now.

Now, a little better explanation of the names:

canvas.save() is saying that I want to save the state of the current Canvas's adjustments so that I can go back to it later.

canvas.restore() is saying that I want to revert my Canvas's adjustments back to the last time I called cavas.save()

The beauty of this is in its simplicity. If you already drew whatever it is you wanted to draw during the save/restore block and you no longer need those adjustment's for your next drawing, using this let's you throw away those unnecessary adjustments and return to the state you want to start your next drawing from.

Hopefully that helps explain it!

Cruceo
  • 6,763
  • 2
  • 31
  • 52
  • 2
    Thank you so much for the explanation. So if we save the state, do the drawing and matrix transformation and then do restore, then we effectivly removed what we did. So when we finish the ondraw, things would be the same as when we started ondraw. So this method was useless then, no? I wouldve imagined that you would do restore whne you start ondraw not restore at the end. I am still missing something here, am i not :)? – Snake Mar 14 '15 at 05:15
  • 1
    "So this method was useless then, no?" - Depends on what you mean by useless. Yes, the next onDraw call will have the un-adjusted state, but that's exactly what you want. When onDraw is called, it means the state of your View has changed and it needs to be redrawn, therefor you want your Canvas at that zeroed-out state, otherwise you'd have to manually figure out how to get it back there in order for you to accurately draw again. Save/restore is hard to understand when you're only doing one task; in fact, it doesn't even make sense to use it in that situation. (continued...) – Cruceo Mar 16 '15 at 14:23
  • 2
    Now, if you're performing several different adjustments to several different objects within the same onDraw method; suddenly save/restore becomes a God-send. Let's say you have object A, B, both at (0,0). You want to move A to (30,0) and B to (0,50). First is easy. translate the canvas to 30. Done. Now the second is where it gets interesting, cuz you're not just going from 0 to 50 in y, you're going 30 to 0 in x, then 0 to 50 in y, so you'd translate (-30,50) instead of our easy (0,50). Now, if you did A's translations inside a save/restore, you'd be able to only translate (continued...) – Cruceo Mar 16 '15 at 14:28
  • 1
    Object B using it's own coordinates, making your job (and the math required to figure everything out) many times less complex. Yeah, with only 2 you could have done that math pretty easily, but imagine having 1000 balls on the screen, each with their own x/y coordinates. You'd have to undo every single adjustment you perform, or drawing the next would become near impossible. So, basically, what I'm trying to say is: for drawing single things don't use it. When drawing multiple things inside your onDraw that make changes to the canvas, that's when you use it cuz it makes your life easier. – Cruceo Mar 16 '15 at 14:34
  • 1
    THANK you so much @Guardanis .. Your example helped a lot. I think I know where the missing point is. When you od a restore, then only the matrix transformation are reset to where they were but the actual drawings are left in place. I thought that it will bring the drawing back to the old place ( or even remove them) and I was so confused why someone would do that. Thank you again for clarifying this dilemma for me – Snake Mar 16 '15 at 20:30
1

Working with the canvas involves all manner of translate,scale,rotate,skew procedures on the canvas. The save() method preserves a state before any of the aforementioned augmentation in place, restore() rewinds to a state in time where no augmentation is injected. In other words, you can save a pre state before any transformation of the canvas, do your rotations and whatever else you want to during the process, but when your finished rewind to the state before any augmentation.

Remario
  • 3,813
  • 2
  • 18
  • 25
1

I guess the simplest way to put it is:

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

chickenz
  • 11
  • 1
0

When you have a background composed of multiple objects, a great way is to save this "static" background and only redraw objects that changed. This saves (processor) time.

avk
  • 871
  • 1
  • 9
  • 22