Canvas.save和Canvas.restore是Android图形绘制中的两个方法。Canvas.save用于保存当前画布的状态,包括画布的变换矩阵、剪切区域等信息。而Canvas.restore则用于恢复之前保存的画布状态,以便进行下一次的绘制操作。这两个方法通常会成对出现使用。

27

1
有趣的事实:我正在使用你的代码库,也在想 save 和 store 是什么意思(顺便说一下,这是 funvas)。 - shadow
1个回答

41

Canvas.saveCanvas.saveLayer 有些微不同,但它们都有相同的对应方法:

Canvas.restore

这使您可以在最近一次保存状态之前恢复状态,即它“弹出当前保存堆栈”。这意味着当前状态下对画布进行的任何变换和裁剪都将被删除,如果使用了saveLayer,则将合成保存的图层到画布中(绘制顺序将保持不变)。

Canvas.save

如我之前所提到的,这允许您保存画布的状态。您可以进行任何想要的转换和裁剪,并可以通过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的所有子项将使用相同的PaintingContext,即相同的Canvas。因此,如果您在单个子项中转换画布,则所有后续绘制的其他子项也将被转换。这是潜在的不良行为,这就是为什么您总是需要saverestore画布状态的原因。

Canvas.saveLayer

这有点复杂,我建议您阅读此方法的全面文档。另外,saveLayer在2019年1月之前无法在Flutter web中使用

saveLayersave的基本区别是,在使用restoresaveLayer将合成图层。举个简单的例子,我构建了此片段不使用bounds(这就是为什么传递null),它将保存整个画布:

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也可以传递给Canvas.drawRect。然而,当使用例如TextPainter时,无法传递混合模式。此外,saveLayer允许您传递边界,这提供了更多可能性(请阅读文档以获取更多信息,还有关于剪辑的)。在使用saveLayer时,剪辑实际上可能是最有用的操作 - 我没有包含它是为了拥有一个简单的示例。

这是没有saveLayer的示例:

屏幕截图


2
我欣赏你有趣的问题和回答。但我想知道为什么你会自己提出这些问题并立即回答它们。写一篇文章不是更合理吗? - J. S.
@JoãoSoares 很好的问题 :) 那么我为什么要创建它们:这个,以及通过这个问题回答了一个Twitter上的问题 - 我实际上在我的问题中链接到了它。通常,当我问自己一些事情并认为让别人知道我的研究成果会很有用时,我就会这样做。例如,结果发现这个问题在我提出问题之后非常受欢迎 - 我能够帮助很多人。 - creativecreatorormaybenot
@JoãoSoares 在那种情况下,我接受自己的答案(以显示问题已有答案),我也可以写文章。我将开始撰写文章 - 我最近写了这篇“测试”文章(也许对您有趣)。然而,在SO上以这种文章风格编写答案有几个好处:它更简洁易懂,可能会帮助更多人,并且期望较低。 - creativecreatorormaybenot
1
谢谢您的回复。我非常感兴趣。我喜欢Flutter并且已经花了很多时间在它上面。学习更多总是很好的,看起来您有很多可以教授的东西。谢谢您的分享。 - J. S.
感谢您提供这篇写得很好的答案。正如您自己所说,您为Canvas.saveLayer提供的示例并不是一个好的用法。在Flutter文档中,他们举了一个例子:“有多个半透明对象”,如果这些对象分别绘制,重叠部分将比通常更暗。使用saveLayer,我们可以在已保存的图层上使用不透明的颜料绘制对象,然后一次性应用不透明度。我认为这将是一个很好的例子,但我找不到一种方法来混合时应用任意的alpha值。您认为他们所说的实际上可行吗? - WSBT
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接