Flutter handling canvas.saveLayer to make layers

37 views Asked by At

I'm trying to make layer function like Photoshop in flutter. For simple implementation, all pictures in a layer are the same color. For example, all drawings on layer 1 are red. But each layer has a different color. For example, layer 1 is red and layer 2 is blue.

Below is the structure of the layers.

import 'package:flutter/material.dart';
import 'package:label_up_study/models/sketch.dart';
import 'dart:math';

Color randomColor() {
  return Color((Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0);
}

class LayerInfo {
  List<Sketch> drawLayer; // This stores every sketch in Listener onPointerDown()/Move()/Up()
  String label;
  bool selected;
  bool visible;
  Color color;

  LayerInfo({
    required this.drawLayer,
    required this.label,
    required this.selected,
    this.visible = true,
    required this.color,
  });
}

class Layers {
  final Map<int, LayerInfo> layers = {};

  int get selected =>
      layers.keys.where((key) => layers[key]!.selected).toList().first;

  void addLayer() {
    final nextKey = layers.keys.toList().last + 1;
    layers.updateAll((key, value) {
      value.selected = false;
      return value;
    });
    layers[nextKey] = LayerInfo(
        drawLayer: [],
        label: 'Layer $nextKey',
        selected: true,
        color: randomColor());
  }

  Layers() {
    layers[1] = LayerInfo(
        drawLayer: [], label: 'Layer 1', selected: true, color: randomColor());
  }
}

I tested canvas.saveLayer like this and this is how I want it to behave: -

There's no overlay with the same layer, but it is distinct with other layer.

So I expected it workes same at below code

class WholeSketchPainter extends CustomPainter {
  final Layers imageLayer;

  WholeSketchPainter({required this.imageLayer});

  @override
  void paint(Canvas canvas, Size size) {
    for (var value in imageLayer.layers.values) {
      print(value.color);
      if (value.visible) {
        canvas.saveLayer(null, Paint()..color = value.color.withOpacity(0.5));
        drawSketch(canvas, value.drawLayer, value.color);
        canvas.restore();
      } else {
        // nothing
      }
    }
  }

  void drawSketch(Canvas canvas, List<Sketch> sketches, Color layerColor) {
    Paint strokePaint = Paint()
      ..style = PaintingStyle.stroke
      ..color = layerColor.withOpacity(1);
    Paint fillPaint = Paint()
      ..style = PaintingStyle.fill
      ..color = layerColor.withOpacity(1);

    for (int i = 0; i < sketches.length; i++) {
      final offsets = sketches[i].points;
      if (offsets.isEmpty) {
        return;
      }
      final path = Path();
      final firstOffset = offsets.first;
      final lastOffset = offsets.last;

      path.moveTo(firstOffset.dx, firstOffset.dy);

      if (sketches[i].sketchType == SketchType.pencil) {
        for (int i = 1; i < offsets.length - 1; i++) {
          final p0 = offsets[i];
          final p1 = offsets[i + 1];
          path.quadraticBezierTo(
              p0.dx, p0.dy, (p0.dx + p1.dx) / 2, (p0.dy + p1.dy) / 2);
        }
        canvas.drawPath(path, fillPaint);
      } else if (sketches[i].sketchType == SketchType.square) {
        final rect = Rect.fromPoints(firstOffset, lastOffset);
        canvas.drawRect(rect, fillPaint);
      }
    }
  }

  @override
  bool shouldRepaint(WholeSketchPainter delegate) {
    return false;
  }
}

BUT IT DOESN'T. It keeps pop up the below layer and cover it.

This is what it looks like with one layer enter image description here

And this is what it looks like with two layers. Color is overlapped, and there's no clip between layers. enter image description here

I want the WholeSketcher code act like the first one, but I have no idea how should I do. Are there any solution to do it? Or anyother way to do it??

+) overall painting code had reference on this: https://github.com/JideGuru/flutter_drawing_board/tree/master

0

There are 0 answers