颤振在具有 CustomPainter 和 InteractiveViewer 的容器中绘图并且无法正确显示

由于我将我的项目迁移到 2.8 版并具有空安全性,因此我遇到了这个错误,我不知道如何解决它;下面我放视频。

enter image description here

我的红色容器尺寸为 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);
  }
}

似乎线条在正确的位置上画得很好,但是我想画我手指所在的位置。

stack overflow Flutter drawing in a container with CustomPainter and InteractiveViewer and not displaying it properly
原文答案
author avatar

接受的答案

好的,我在不更改小部件的情况下纠正了我的错误,我唯一做的就是创建一个 InteractiveViewer 控制器,然后我就以这种方式获得了 General Offset:

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

答案:

作者头像

我过去做过这件事,我可以建议我当时做了什么。

首先我会使用 GestureDetector 而不是 InterActiveViewer 。使用它的 onPanUpdate 方法来添加这样的偏移量,

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

offsets 是您用来绘制的主要偏移变量。

我在自定义画家中使用的 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

或者你可以使用这个包 perfect_freehand

作者头像

我在不更改小部件的情况下纠正了我的错误,我唯一做的就是创建一个 InteractiveViewer 控制器。