Что такое Canvas.save и Canvas.restore? - PullRequest
3 голосов
/ 08 января 2020

Мне интересно , почему и когда вы бы использовали Canvas.save, Canvas.restore и, возможно, даже Canvas.saveLayer .
Я слышал, что они действительно полезны, но я не знаю, когда их использовать.

1 Ответ

5 голосов
/ 08 января 2020

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.

Вы можете использовать любое число save до restore, и стек запомнит все записи, то есть restore будет всегда выдвиньте самую последнюю запись.

Когда бы я использовал это?

Пример: если вы хотите повернуть один фрагмент при рисовании большего изображения, вы можете просто сделать вращение внутри save - restore заблокируйте и нарисуйте что-нибудь без вращения сверху.

Обратите внимание, что все потомков из RenderObject будут использовать одинаковые PaintingContext т.е. то же самое Canvas. Таким образом, если вы преобразуете холст в одном дочернем элементе, он также будет преобразован для всех остальных дочерних элементов, которые рисуют впоследствии. Это потенциально нежелательное поведение и причина, по которой вы всегда хотите save и restore состояние холста.

Canvas.saveLayer

Это немного больше сложный, и я призываю вас прочитать всеобъемлющую документацию по этому методу. Кстати, 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.

Screen capture

Обратите внимание, что синий прямоугольник будет по-прежнему накладываться над красным прямоугольником.

Этот пример также может быть достигнут без использования saveLayer, поскольку Paint.blendMode Используемый мной также может быть передан в Canvas.drawRect. Однако при использовании, например, TextPainter, вы не можете пройти режимы наложения. Кроме того, saveLayer позволяет вам проходить границы, что дает гораздо больше возможностей (см. Документацию для получения дополнительной информации, также о клипах ). Отсечение на самом деле, вероятно, самая полезная операция в сочетании с saveLayer - я не включил ее, чтобы получить простой пример.

Так будет выглядеть пример без saveLayer:

Screen capture

...