简体   繁体   English

Flutter 使用 CustomPainter 和 InteractiveViewer 在容器中绘图,但无法正确显示

[英]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;由于我将我的项目迁移到 2.8 版并具有空安全性,因此我遇到了这个错误,我不知道如何解决它; below I put the video.下面我放视频。

在此处输入图像描述

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).我的红色容器尺寸为 1700 x 1200,我将相同的测量值发送到 CustomPainter,但是似乎在绘图时,它需要我手机的测量值,因为当我缩放它时(这就是我使用交互式缩放它的原因),它仍然有相同的测量值(我不知道它是什么)。

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.看起来线条在右侧 position 上画得很好,但是我想画我手指所在的位置。

I have done this in past and I can suggest what I did at that time.我过去做过这件事,我可以建议我当时做了什么。

first I would use GestureDetector rather than InterActiveViewer .首先我会使用GestureDetector而不是InterActiveViewer Use it's onPanUpdate method to add offsets like this maybe,使用它的onPanUpdate方法来添加这样的偏移量,

setState(() {
                RenderBox object = context.findRenderObject();
                Offset _localPosition =
                    object.globalToLocal(details.globalPosition);
                offsets = List.from(offsets)..add(_localPosition);
              });

offsets is your main offset variable which you use to draw. offsets 是您用来绘制的主要偏移变量。

and the for loop which I used in custom painter is this,我在自定义画家中使用的 for 循环是这个,

 for (int i = 0; i < offsets.length - 1; i++) {
      if (offsets[i] != null && offsets[i + 1] != null) {
        canvas.drawLine(offsets[i], offsets[i + 1], paint);
      }
    }

remove your code for starts at first point

or you can use this package perfect_freehand或者你可以使用这个 package perfect_freehand

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:好的,我在不更改小部件的情况下纠正了我的错误,我唯一做的就是创建一个 InteractiveViewer Controller,然后我就这样得到了 General Offset:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM