Flutter垃圾管理APP:如何获取Custom Paint绘制的矩形位置(GetX)
垃圾管理APP矩形框选位置获取问题
我正在开发一款垃圾管理APP,用户拍摄图片后可在界面中用矩形框选垃圾区域。目前用Stack结合Custom Paint实现绘制功能,采用GetX状态管理,但无法获取绘制完成的矩形位置,而这些位置需要传入ML模型做后续处理。
界面代码
body: SizedBox( width: double.maxFinite, child: GetBuilder(builder: (DetectTrashController controller) { return Stack( children: [ GestureDetector( onPanStart: (details) { controller.startDrawing(details.localPosition); }, onPanUpdate: (details) { controller.updateDrawing(details.localPosition); }, onPanEnd: (details) { controller.endDrawing(); }, child: Stack( children: [ Image.file( fit: BoxFit.cover, height: double.maxFinite, width: double.maxFinite, File(controller.imagePath!), ), SizedBox( height: controller.image!.height.toDouble(), width: controller.image!.width.toDouble(), child: CustomPaint( key: controller.widgetKey, painter: RectanglePainter( controller.rectangles, controller.currentRect, controller.image!, ), size: Size.infinite, ), ), Padding( padding: const EdgeInsets.all(8), child: Align( alignment: Alignment.topLeft, child: InkWell( onTap: () { controller.toggleDrawing(); }, child: Container( height: 31.v, width: 161.h, color: whiteColor, child: Obx( () => Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Checkbox( checkColor: whiteColor, fillColor: MaterialStatePropertyAll( controller.drawingEnabled.value ? Colors.black : null), shape: controller.drawingEnabled.value ? const CircleBorder() : null, value: controller.drawingEnabled.value, onChanged: (value) { controller.toggleDrawing(); }, ), Text(controller.drawingEnabled.value ? "Cancel Selection" : "Draw Selection"), ], ), )), ), ), ), ], ), ), Padding( padding: EdgeInsets.only(bottom: 10.v), child: Align( alignment: Alignment.bottomCenter, child: CustomElevetedButton( onPressed: () {}, backgroundColor: primaryColor, child: "Update", size: Size(189.h, 40.v), ), ), ) ], ); }), ),
CustomPaint 类代码
class RectanglePainter extends CustomPainter { final List<Rectangle> rectangles; final Rect? currentRect; RectanglePainter(this.rectangles, this.currentRect,); @override void paint(Canvas canvas, Size size) { final paint = Paint() ..color = Colors.red ..strokeWidth = 2 ..style = PaintingStyle.stroke; // 绘制已完成的矩形 for (var rectangle in rectangles) { canvas.drawRect(rectangle.rect, paint); } // 绘制正在拖动的当前矩形 if (currentRect != null) { canvas.drawRect(currentRect!, paint); } } @override bool shouldRepaint(covariant CustomPainter oldDelegate) { return true; // 每次都重绘以反映变化 } }
实现效果

解决方法
核心问题是你已经在Controller中维护了rectangles列表存储已完成的矩形,但需要正确暴露并转换这些坐标,适配ML模型需要的原始图片像素位置(注意界面图片拉伸的影响)。
确认Controller正确存储绘制完成的矩形
检查DetectTrashController的endDrawing方法,确保已将绘制完成的currentRect添加到rectangles列表:void endDrawing() { if (currentRect != null && drawingEnabled.value) { rectangles.add(Rectangle(currentRect!)); // 假设Rectangle类持有Rect对象 currentRect = null; update(); // 通知GetBuilder刷新界面 } }转换界面坐标为原始图片坐标
界面中图片用BoxFit.cover拉伸显示,绘制的矩形是界面坐标,需要转换为原始图片的真实像素坐标:
在Controller中添加转换方法:List<Rect> getOriginalImageRects() { final imageSize = Size(image!.width.toDouble(), image!.height.toDouble()); final widgetSize = widgetKey.currentContext!.size!; // 计算图片在界面上的实际显示区域(适配BoxFit.cover的拉伸逻辑) final scale = max(widgetSize.width / imageSize.width, widgetSize.height / imageSize.height); final scaledImageSize = imageSize * scale; final dx = (widgetSize.width - scaledImageSize.width) / 2; final dy = (widgetSize.height - scaledImageSize.height) / 2; return rectangles.map((rect) { // 将界面坐标转换为原始图片坐标 final adjustedRect = Rect.fromLTWH( (rect.rect.left - dx) / scale, (rect.rect.top - dy) / scale, rect.rect.width / scale, rect.rect.height / scale, ); // 确保坐标不超出原始图片范围 return adjustedRect.intersect(Rect.fromLTWH(0, 0, imageSize.width, imageSize.height)); }).toList(); }获取坐标传入ML模型
在"Update"按钮的点击事件中调用转换方法,拿到适配原始图片的矩形坐标:onPressed: () { final originalRects = controller.getOriginalImageRects(); // 将originalRects传入ML模型处理,示例: // mlModel.processImageWithRects(controller.imagePath!, originalRects); },验证坐标正确性
可以打印转换后的坐标,对比原始图片的像素位置,确保矩形区域和用户框选的范围一致。
内容的提问来源于stack exchange,提问作者Muhmmad Nawaz Shah
相关产品推荐
相关产品推荐

