Search code examples
flutterdartcustom-painter

Flutter drawing in a container with CustomPainter and InteractiveViewer and not displaying it properly


Since I migrated my project to version 2.8 and with null-safety, I have had this error which I do not know how to solve it; below I put the video.

enter image description here

My red container measures 1700 x 1200, I sent that same measurement to CustomPainter, however it seems that when drawing, it takes the measurement of my phone because when I zoom it (that's why i use Interactive, to zoom it), it still has the same measurement (I do not know what it is).

DrawnShape? currentShape; //My object

return InteractiveViewer(
      /// * START
      onInteractionStart: (details) {
         currentShape = DrawnShape(
           pointList: [],
           paint: Paint()
             ..strokeCap = StrokeCap.round
             ..isAntiAlias = true
             ..color = Colors.black
             ..strokeWidth = 3.0
             ..style = PaintingStyle.stroke,
           type: 1,
           id: Uuid(),
         );
      },

      /// * UPDATE
      onInteractionUpdate: (details) {
        currentShape.pointList.add(details.localFocalPoint);

        // Some Bloc that returns a List<DrawnShape> in a DrawUpdate state
        // and then go to the Class MyCanvas
        BlocProvider.of<DrawBloc>(context).add(AddShapeEvent(
          currentShape,
        ));
      },

      /// * END
      onInteractionEnd: (details) {
         currentShape = null;
      },

      constrained: false,
      boundaryMargin: EdgeInsets.all(1200 * 0.2);,
      maxScale: 5,
      minScale: 0.1,

      // * STACK
      child: Stack(
        children: [
          SizedBox(
            height: 1700,
            width: 1200,
            child: Container(
              decoration: BoxDecoration(
                color: Colors.red,
                border: new Border.all(
                  color: Colors.grey, width: 1.5, style: BorderStyle.solid),
                ),
              child: Text(""),
            ),
          );

          // * CANVAS TO DRAW ON
          IgnorePointer(
            ignoring: true,
            child: MyCanvas(
              height: 1700,
              width: 1200,
            ),
          ),
        ],
      ),
    );


class MyCanvas extends StatelessWidget {
  final double height;
  final double width;

  const MyCanvas({
    Key? key,
    this.height,
    this.width,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final canvasSize = Size(width, height);

    return ClipRect(
      // * CONSUMER
      child: BlocConsumer<DrawBloc, DrawBlocState>(
        listener: (context, state) {},
        builder: (context, state) {
          // * DRAWING UPDATED
          if (state is DrawUpdate) {
            // * CUSTOM PAINT
            return CustomPaint(
                isComplex: true,
                size: canvasSize,
                // * DRAWING PAINTER
                painter: DrawingPainter(
                  state.lineList,
                ),
          } else {
            return Container();
          }
        },
      ),
    );
  }
}

//===========================================================================
// * DRAWING PAINTER (canvas to paint on)
//
class DrawingPainter extends CustomPainter {
  DrawingPainter(
    this.shapeList,
  );

  final List<DrawnShape> shapeList;

  @override
  void paint(Canvas canvas, Size size) {

    canvas.saveLayer(Rect.fromLTWH(0, 0, size.width, size.height), Paint());

    for (int i = 0; i < shapeList.length; i++) {
      final currentShape = shapeList[i];

      switch (currentShape.type) {
        // case ActionType.RECTANGLE:
        //   this._drawRectangle(canvas, currentShape);
        //   break;
        // case ActionType.CIRCLE:
        //   this._drawCircle(canvas, currentShape);
        //   break;
        // case ActionType.CLOUD:
        //   this._drawCloud(canvas, currentShape);
        //   break;
        default:
          this._drawFromPointList(canvas, currentShape); // THE IMPORTANT
          break;
      }
    }
    canvas.restore();
  }

  @override
  bool shouldRepaint(DrawingPainter oldDelegate) => true;


  //===========================================================================
  // POINT LIST
  //
  void _drawFromPointList(Canvas canvas, DrawnShape currentShape) {
    final Path path = Path();
    final pointList = currentShape.pointList;

    /// starts at first point
    path.moveTo(
      pointList[0].dx,
      pointList[0].dy,
    );

    /// goes through every point of the line, (starts at 1)
    for (int f = 1; f < pointList.length; f++)
      path.lineTo(pointList[f].dx, pointList[f].dy);

    /// draw the line
    canvas.drawPath(path, currentShape.paint);
  }
}

It seems that the lines paint well in the right position, however I want to paint where my finger is.


Solution

  • Ok, I have corrected my mistake without changing widget, the only thing I did was to create an InteractiveViewer Controller, and then I just got the General Offset this way :

    final scenePoint =
            _transformationController.toScene(details.localFocalPoint);