canvas.saveLayer with BlendMode.clear not show pointer movement

47 views Asked by At

I have flutter drawing app, in which i use drawing on layers. I'm stuck with implementing eraser in program, the problem is that when i am drawing current path and using eraser, i don't see the pointer movement on canvas, i only see the result erased path when pointer is up. While i draw usual path, not erasing, the movement is visible. I use canvas.saveLayer, BlendMode.clear and canvas.restore if the path was done "in eraser mode".

Here is my custom Painter for drawing current path:

class SingleLinePainter extends CustomPainter {
  final Stroke? line;
  final StrokeOptions options;
  Color currentColor = Colors.black;

  SingleLinePainter(
      {required this.currentColor, required this.line, required this.options});

  void setColorForLayer(Color color) {
    currentColor = color;
  }

  @override
  Future<void> paint(Canvas canvas, Size size) async {
    Paint paint = Paint();
    var _blendMode = BlendMode.srcOver;

    if (line!.isEraser) {
      canvas.saveLayer(null, Paint());

      _blendMode = BlendMode.clear;
    }
    paint.blendMode = _blendMode;
    paint.color = currentColor;

    final outlinePoints = getStroke(
      line!.points,
      size: options.size,
      thinning: options.thinning,
      smoothing: options.smoothing,
      streamline: options.streamline,
      taperStart: options.taperStart,
      capStart: options.capStart,
      taperEnd: options.taperEnd,
      capEnd: options.capEnd,
      simulatePressure: options.simulatePressure,
      isComplete: options.isComplete,
    );

    final path = Path();

    if (outlinePoints.isEmpty) {
      return;
    } else if (outlinePoints.length < 2) {

      path.addOval(Rect.fromCircle(
          center: Offset(outlinePoints[0].x, outlinePoints[0].y), radius: 1));
    } else {

      path.moveTo(outlinePoints[0].x, outlinePoints[0].y);

      for (int i = 1; i < outlinePoints.length - 1; ++i) {
        final p0 = outlinePoints[i];

        final p1 = outlinePoints[i + 1];
        path.quadraticBezierTo(
            p0.x, p0.y, (p0.x + p1.x) / 2, (p0.y + p1.y) / 2);
      }
    }

    canvas.drawPath(path, paint);
    if (line!.isEraser) {
      canvas.restore();
    }
  }

  @override
  bool shouldRepaint(SingleLinePainter oldDelegate) {
    return true;
  }
}

My widget for building current path:

Widget buildCurrentPath(BuildContext context) {
    return Listener(
      onPointerDown: onPointerDown,
      onPointerMove: onPointerMove,
      onPointerUp: onPointerUp,
      child: RepaintBoundary(
        child: Container(
            color: Colors.transparent,
            width: widget.width,
            height: widget.height,
            child: StreamBuilder<Stroke>(
                stream: currentLineStreamController.stream,
                builder: (context, snapshot) {
                  return CustomPaint(
                    painter: SingleLinePainter(
                      currentColor: pickerColor,
                      line: line == null ? null : line!,
                      options: options,
                    ),
                  );
                })),
      ),
    );
  }

If i don't use canvas.saveLayer + canvas.restore, i will see the pointer movement, but the eraser will erase path through all previous layers (for simplifying just imagine that i'm drawing on background image, and this path will erase it), but i want to erase path only on current layer.

0

There are 0 answers