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.