什么是 Canvas.save 和 Canvas.restore?
What is Canvas.save and Canvas.restore?
我在想why and when you would use Canvas.save
, Canvas.restore
, and maybe even Canvas.saveLayer
。
听说很好用,就是不知道什么时候用。
Canvas.save
和 Canvas.saveLayer
的工作方式略有不同,但它们都有相同的对应物:
Canvas.restore
这允许您恢复保存堆栈上最近条目之前的状态,即它“弹出当前保存堆栈”。这意味着在当前状态下对 canvas 所做的任何转换和剪辑都将被删除,如果使用了 saveLayer
,保存的图层将被合成到 canvas(绘制顺序将保持不变)。
Canvas.save
正如我之前提到的,这允许您保存 canvas 所处的状态。您可以执行任何 transformation 和 clips 你想要的,那些将被删除使用 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.
您可以在 restore
之前使用任意数量的 save
并且堆栈将记住所有条目,即 restore
将始终弹出最近的条目。
我什么时候用这个?
例子:如果你想在画大图的时候旋转一个单块,你可以简单地在save
-restore
块内旋转,然后在上面画一些没有旋转的东西.
注意一个RenderObject
的所有children将使用相同的PaintingContext
,即相同的Canvas
。因此,如果您在单个 child 中转换 canvas,它也会为之后绘制的所有其他 children 进行转换。这可能是不需要的行为,也是您总是希望 save
和 restore
处于 canvas 状态的原因。
Canvas.saveLayer
这有点复杂,我强烈建议您阅读此方法的综合文档。顺便说一句,saveLayer
does not work in Flutter web as of January, 2019.
saveLayer
和 save
的基本区别在于 saveLayer
将在使用 restore
时合成图层。举个简单的例子,我构建了这个片段 without bounds
(这就是 null
被传递的原因),它将保存整个 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.
请注意,蓝色矩形仍将合成在红色矩形上方。
这个例子也可以在不使用 saveLayer
的情况下实现,因为 Paint.blendMode
I used can also be passed to Canvas.drawRect
. However, when using e.g. a TextPainter
,你不能通过混合模式。此外,saveLayer
允许您传递边界,这提供了更多可能性(阅读文档以获取更多信息,还有关于 clips 的信息) . 剪辑 实际上可能是与 saveLayer
结合使用时最有用的操作 - 我没有包括它是为了有一个简单的例子。
如果没有 saveLayer
:
,示例将是这样的
我在想why and when you would use Canvas.save
, Canvas.restore
, and maybe even Canvas.saveLayer
。
听说很好用,就是不知道什么时候用。
Canvas.save
和 Canvas.saveLayer
的工作方式略有不同,但它们都有相同的对应物:
Canvas.restore
这允许您恢复保存堆栈上最近条目之前的状态,即它“弹出当前保存堆栈”。这意味着在当前状态下对 canvas 所做的任何转换和剪辑都将被删除,如果使用了 saveLayer
,保存的图层将被合成到 canvas(绘制顺序将保持不变)。
Canvas.save
正如我之前提到的,这允许您保存 canvas 所处的状态。您可以执行任何 transformation 和 clips 你想要的,那些将被删除使用 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.
您可以在 restore
之前使用任意数量的 save
并且堆栈将记住所有条目,即 restore
将始终弹出最近的条目。
我什么时候用这个?
例子:如果你想在画大图的时候旋转一个单块,你可以简单地在save
-restore
块内旋转,然后在上面画一些没有旋转的东西.
注意一个RenderObject
的所有children将使用相同的PaintingContext
,即相同的Canvas
。因此,如果您在单个 child 中转换 canvas,它也会为之后绘制的所有其他 children 进行转换。这可能是不需要的行为,也是您总是希望 save
和 restore
处于 canvas 状态的原因。
Canvas.saveLayer
这有点复杂,我强烈建议您阅读此方法的综合文档。顺便说一句,saveLayer
does not work in Flutter web as of January, 2019.
saveLayer
和 save
的基本区别在于 saveLayer
将在使用 restore
时合成图层。举个简单的例子,我构建了这个片段 without bounds
(这就是 null
被传递的原因),它将保存整个 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.
请注意,蓝色矩形仍将合成在红色矩形上方。
这个例子也可以在不使用 saveLayer
的情况下实现,因为 Paint.blendMode
I used can also be passed to Canvas.drawRect
. However, when using e.g. a TextPainter
,你不能通过混合模式。此外,saveLayer
允许您传递边界,这提供了更多可能性(阅读文档以获取更多信息,还有关于 clips 的信息) . 剪辑 实际上可能是与 saveLayer
结合使用时最有用的操作 - 我没有包括它是为了有一个简单的例子。
如果没有 saveLayer
: