dnfield / flutter_svg

SVG parsing, rendering, and widget library for Flutter
MIT License
1.68k stars 459 forks source link

Blend mode between two SVG #557

Open dan-leech opened 3 years ago

dan-leech commented 3 years ago

Maybe I do not understand blending right... I have two svg with shapes of different colors.

<svg width="22" height="19" viewBox="0 0 22 19" fill="#00FF00" xmlns="http://www.w3.org/2000/svg">
    <path d="M11.3044 18.8246H3.61473C1.51756 18.8246 0.219298 16.5277 1.21795 14.7302L5.11271 8.03916L9.00746 1.34818C10.106 -0.449394 12.7025 -0.449394 13.7011 1.34818L17.5959 8.03916L21.4906 14.7302C22.5891 16.5277 21.191 18.8246 19.0939 18.8246H11.3044Z"/>
</svg>

What is working and how:

What's the proper way to achieve something like this between two different SvgPicture widgets?

dan-leech commented 3 years ago

I've found the way to achieve this:

BlendMask(
  opacity: _spotOpacity.value,
  blendMode: _blendMode,
  child: SvgPicture.asset('assets/triangle.svg'));
class BlendMask extends SingleChildRenderObjectWidget {
  final BlendMode blendMode;
  final double opacity;

  const BlendMask({
    required this.blendMode,
    required Widget child,
    this.opacity = 1.0,
    Key? key,
  }) : super(key: key, child: child);

  @override
  RenderObject createRenderObject(BuildContext context) =>
      RenderBlendMask(blendMode, opacity);

  @override
  void updateRenderObject(BuildContext context, RenderBlendMask renderObject) {
    renderObject
      ..blendMode = blendMode
      ..opacity = opacity;
  }
}

class RenderBlendMask extends RenderProxyBox {
  BlendMode blendMode;
  double opacity;

  RenderBlendMask(this.blendMode, this.opacity);

  @override
  void paint(PaintingContext context, Offset offset) {
    context.canvas.saveLayer(
        offset & size,
        Paint()
          ..blendMode = blendMode
          ..color = Color.fromARGB((opacity * 255).round(), 255, 255, 255));

    super.paint(context, offset);

    context.canvas.restore();
  }
}