Canvas.save
и Canvas.saveLayer
работают немного по-разному, но оба имеют одинаковый аналог:
Это позволяет восстановить состояние перед самой последней записью в стеке сохранения, т.е. она " выводит текущий стек сохранения ". Это означает, что любые преобразования и клипы, выполненные на холсте в текущем состоянии, будут удалены, и если использовалось saveLayer
, сохраненный слой будет объединен с холстом (порядок рисования останется прежним).
Как я уже упоминал ранее, это позволяет сохранить состояние, в котором находится холст. Вы можете делать любые преобразования и клипы вы хотите, и они будут удалены с помощью 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.
Вы можете использовать любое число save
до restore
, и стек запомнит все записи, то есть restore
будет всегда выдвиньте самую последнюю запись.
Когда бы я использовал это?
Пример: если вы хотите повернуть один фрагмент при рисовании большего изображения, вы можете просто сделать вращение внутри save
- restore
заблокируйте и нарисуйте что-нибудь без вращения сверху.
Обратите внимание, что все потомков из RenderObject
будут использовать одинаковые PaintingContext
т.е. то же самое Canvas
. Таким образом, если вы преобразуете холст в одном дочернем элементе, он также будет преобразован для всех остальных дочерних элементов, которые рисуют впоследствии. Это потенциально нежелательное поведение и причина, по которой вы всегда хотите save
и restore
состояние холста.
Это немного больше сложный, и я призываю вас прочитать всеобъемлющую документацию по этому методу. Кстати, saveLayer
не работает в Флаттер по состоянию на январь 2019 года .
Основа c разница между saveLayer
и save
составляет saveLayer
будет составлять слой при использовании 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.
Обратите внимание, что синий прямоугольник будет по-прежнему накладываться над красным прямоугольником.
Этот пример также может быть достигнут без использования saveLayer
, поскольку Paint.blendMode
Используемый мной также может быть передан в Canvas.drawRect
. Однако при использовании, например, TextPainter
, вы не можете пройти режимы наложения. Кроме того, saveLayer
позволяет вам проходить границы, что дает гораздо больше возможностей (см. Документацию для получения дополнительной информации, также о клипах ). Отсечение на самом деле, вероятно, самая полезная операция в сочетании с saveLayer
- я не включил ее, чтобы получить простой пример.
Так будет выглядеть пример без saveLayer
: