什么是 Canvas.save 和 Canvas.restore?

cre*_*not 17 skia dart flutter

我想知道您为什么以及何时会使用Canvas.save, Canvas.restore,甚至Canvas.saveLayer.
我听说它们真的很有用,但我不知道什么时候使用它们。

cre*_*not 22

Canvas.save并且Canvas.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.
Run Code Online (Sandbox Code Playgroud)

您可以使用任意数量的savebefore restore,堆栈将记住所有条目,即restore始终弹出最近的条目。

我什么时候用这个?

示例:如果您想在绘制更大的图片时旋转单个部分,您可以简单地在save-restore块内进行旋转,然后在顶部绘制一些没有旋转的东西。

请注意, a 的所有RenderObject都将使用相同的PaintingContext,即相同的Canvas。因此,如果您在单个子级中转换画布,它也会为之后绘制的所有其他子级转换。这是潜在的有害行为,也是您总是想要saverestore画布状态的原因。

Canvas.saveLayer

这有点复杂,我强烈建议您阅读此方法的综合文档。顺便说一句,截至 2019 年 1 月,saveLayer Flutter web 中不起作用

saveLayer和之间的基本区别savesaveLayer将在使用restore. 举个简单的例子,我在没有 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.
Run Code Online (Sandbox Code Playgroud)

屏幕截图

请注意,蓝色矩形仍将合成在红色矩形上方。

这个例子也可以不用 using 来实现,saveLayer因为Paint.blendModeI used 也可以传递给Canvas.drawRect. 但是,当使用例如 a 时TextPainter,您不能传递混合模式。此外,saveLayer允许您传递边界,这提供了更多的可能性(阅读文档了解更多信息,也关于剪辑)。剪裁实际上可能是结合使用最有用的操作saveLayer- 我没有包括它是为了有一个简单的例子。

这是示例在没有的情况下的外观saveLayer

屏幕截图

  • 我很欣赏你有趣的问题和答案。但我想知道你为什么提出这些问题并立即回复它们。写一篇关于它的文章不是更有意义吗? (2认同)