Flutter: как правильно применить ImageFilter к текущему слою?

#flutter #canvas #imagefilter

Вопрос:

Я пытаюсь применить последовательность ImageFilter s к текущему нарисованному Canvas слою.

 canvas.drawCircle(...)
canvas.drawCircle(...)

// TODO Apply ImageFilter 1: Blur
// TODO Apply ImageFilter 2: Blur again

 

Есть ли простой способ сделать это? Вероятно, мне не хватает какого-то простого метода, но я ничего не смог найти…


Вещи, которые я пробовал:

Я знаю, что могу указать объединенные ImageFilter в Paint , но это не работает — я хочу применять их последовательно после того, как все фигуры будут нарисованы, а к каждой фигуре отдельно.

saveLayer кажется, это ближе всего к достижению того, что мне нужно, но, согласно документам, это применимо только ColorFilter . Они также говорят, что это немного неэффективно.

 saveLayer(null, Paint()..colorFilter = filter2)
saveLayer(null, Paint()..colorFilter = filter1)
..
canvas.draw
canvas.draw
...
restore()
restore()
 

Спасибо!

Комментарии:

1. Спасибо, это применит эффект к каждой нарисованной фигуре отдельно. Я нашел кое-что в то же время PaintingContext.addLayer может быть решением, попробовав его…

2. Да, спасибо, мне удалось сделать это со слоями и полем рендеринга.

Ответ №1:

Для дальнейшего использования я смог добиться желаемого эффекта с помощью RenderBox (это можно использовать, например, из LeafRenderObjectWidget ).

RenderBox Имеет метод рисования:

 @override
void paint(PaintingContext context, Offset offset) {
    context.pushLayer(
      ColorFilterLayer(colorFilter: ColorFilter.matrix(...)),
      (PaintingContext context2, Offset offset2) => 
          context2.pushLayer(
            ImageFilterLayer(imageFilter: ui.ImageFilter.blur(...)),
            (PaintingContext context3, Offset offset3) =>
                simulation.draw(context3.canvas),
            offset2),
      offset);
 

Не то, что simulation.draw(context3.canvas) будет отображаться на холсте, за которым следует размытие ImageFilter , а затем ColorFilter . Layers Можно добавить любое количество, хотя синтаксис немного болезненный. При необходимости его можно упростить с некоторыми усилиями:

 /// Returns the painter with the given layer applied.
PaintingContextCallback withLayer(
    ContainerLayer layer, PaintingContextCallback painter) {
  return (PaintingContext context, Offset offset) =>
      context.pushLayer(layer, painter, offset);
}

...
final List<ContainerLayer> layers = [...];
var painter = ...
for (final layer in layers) {
  painter = withLayer(layer, painter);
}
painter(context, offset);
 

Комментарии:

1. Спасибо, уже намного чище! В моем случае я применял переменное количество фильтров, поэтому в итоге я получил простую вспомогательную функцию, обновил ответ.

2. Ваша вставка имеет тайм-аут, поэтому не может включать ее в качестве альтернативного предложения: (Я думаю, что в некоторых случаях ваш может быть лучше.