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.
您可以在restore
之前使用任意数量的save
,堆栈将记住所有条目,即restore
将始终弹出最近的条目。
例如:如果您想要在绘制较大的图片时旋转单个图块,则可以简单地在save
-restore
块中执行旋转,并在顶部绘制不带旋转的内容。
请注意,RenderObject
的所有子项将使用相同的PaintingContext
,即相同的Canvas
。因此,如果您在单个子项中转换画布,则所有后续绘制的其他子项也将被转换。这是潜在的不良行为,这就是为什么您总是需要save
和restore
画布状态的原因。
Canvas.saveLayer
这有点复杂,我建议您阅读此方法的全面文档。另外,saveLayer
在2019年1月之前无法在Flutter web中使用。
saveLayer
和save
的基本区别是,在使用restore
时saveLayer
将合成图层。举个简单的例子,我构建了此片段不使用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
的示例:
Canvas.saveLayer
提供的示例并不是一个好的用法。在Flutter文档中,他们举了一个例子:“有多个半透明对象”,如果这些对象分别绘制,重叠部分将比通常更暗。使用saveLayer
,我们可以在已保存的图层上使用不透明的颜料绘制对象,然后一次性应用不透明度。我认为这将是一个很好的例子,但我找不到一种方法来混合时应用任意的alpha值。您认为他们所说的实际上可行吗? - WSBT