Flutter 形状调整大小并拖动背景图像 canvas

Flutter shape resizing and dragging over image back-grounded canvas

我想在图像背景上创建不同类型的形状(如矩形、直线或圆形)canvas 并使用角点编辑这些形状以调整大小。我怎样才能用 flutter 做到这一点?

Shapes自定义拖角与此JavaScript框架类似Fabric.js

结果应该是这样的:

我通过编写以下代码解决了这个问题:

来自 Scaffold 的代码的第一部分:

if (_imageWidget != null) ...[
            FittedBox(
              fit: BoxFit.fill,
              child: GestureDetector(
                onPanStart: (DragStartDetails details) {
                  // get distance from points to check if is in circle
                  int indexMatch = -1;
                  for (int i = 0; i < _points.length; i++) {
                    double distance = sqrt(
                        pow(details.localPosition.dx - _points[i].dx, 2) +
                            pow(details.localPosition.dy - _points[i].dy, 2));
                    if (distance <= 30) {
                      indexMatch = i;
                      break;
                    }
                  }
                  if (indexMatch != -1) {
                    _currentlyDraggedIndex = indexMatch;
                  }
                },
                onPanUpdate: (DragUpdateDetails details) {
                  if (_currentlyDraggedIndex != -1) {
                    setState(() {
                      _points = List.from(_points);
                      _points[_currentlyDraggedIndex] = details.localPosition;
                    });
                  }
                },
                onPanEnd: (_) {
                  setState(() {
                    _currentlyDraggedIndex = -1;
                  });
                },
                child: SizedBox(
                  width: _image.width.toDouble(),
                  height: _image.height.toDouble(),
                  child: CustomPaint(
                    painter: RectanglePainter(
                        points: _points, clear: _clear, image: _image),
                  ),
                ),
              ),
            )
          ]

第二部分

class RectanglePainter extends CustomPainter {
  List<Offset> points;
  bool clear;
  final ui.Image image;

  RectanglePainter(
      {@required this.points, @required this.clear, @required this.image});

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.red
      ..strokeCap = StrokeCap.square
      ..style = PaintingStyle.fill
      ..strokeWidth = 2;

    final outputRect =
        Rect.fromPoints(ui.Offset.zero, ui.Offset(size.width, size.height));
    final Size imageSize =
        Size(image.width.toDouble(), image.height.toDouble());
    final FittedSizes sizes =
        applyBoxFit(BoxFit.contain, imageSize, outputRect.size);
    final Rect inputSubrect =
        Alignment.center.inscribe(sizes.source, Offset.zero & imageSize);
    final Rect outputSubrect =
        Alignment.center.inscribe(sizes.destination, outputRect);
    canvas.drawImageRect(image, inputSubrect, outputSubrect, paint);
    if (!clear) {
      final circlePaint = Paint()
        ..color = Colors.red
        ..strokeCap = StrokeCap.square
        ..style = PaintingStyle.fill
        ..blendMode = BlendMode.multiply
        ..strokeWidth = 2;

      for (int i = 0; i < points.length; i++) {
        if (i + 1 == points.length) {
          canvas.drawLine(points[i], points[0], paint);
        } else {
          canvas.drawLine(points[i], points[i + 1], paint);
        }
        canvas.drawCircle(points[i], 10, circlePaint);
      }
    }
  }

  @override
  bool shouldRepaint(RectanglePainter oldPainter) =>
      oldPainter.points != points || clear;
}