實現原理很簡單 ,自己繪制一個裁剪框, 根據手勢 選擇到適合的位置 ,然后將選中的區域繪制到一個新的圖片上,從而完成裁剪
裁剪框的繪制 這里我是根據點來連線的 因為每個點上會繪制一個拉伸的標識符
List<Offset> points2 = [ Offset(startX, startY), Offset(startX + cWidth, startY), Offset(startX + cWidth, startY + cHeight), Offset(startX, startY + cHeight), Offset(startX, startY), ]; canvas.drawPoints(PointMode.polygon, points2, paint);//draw the clip box paint.color = Colors.red; // paint..style=PaintingStyle.stroke; double radius = 10; canvas.drawCircle(points2[0],radius,paint); //draw the drag point canvas.drawCircle(points2[1],radius,paint); canvas.drawCircle(points2[2],radius,paint); // canvas.drawLine(Offset(points2[2].dx-radius, points2[2].dy-radius), Offset(points2[2].dx+radius, points2[2].dy+radius), paint); canvas.drawCircle(points2[3],radius,paint);
源圖片的繪制 ,根據屏幕大小 把圖片縮放成適合長寬比例的圖片
if (image != null) { //draw the backgroud image double dwidth = 0; double dheight = 0; if (image.width.toDouble() / width > image.height.toDouble() / height) { dwidth = width; dheight = image.height.toDouble() * dwidth / image.width.toDouble(); } else { dheight = height; dwidth = image.width.toDouble() * dheight / image.height.toDouble(); } if (points.length > 0) { points[3] = Offset(dwidth, dheight); } canvas.drawImageRect(image, Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble()), Rect.fromLTWH((width - dwidth) / 2, (height - dheight) / 2, dwidth, dheight), paint); }
繪制完后 就是根據手勢的偏移量來計算裁剪框的大小位置
GestureDetector( onPanDown: onPanDown, onPanUpdate:onPanUpdate, onPanEnd: onPanEnd, ),
List<Offset> _points = <Offset>[];
_points有4個值 [0] 代表down的坐標 [1]代表move的左邊 [2]代表裁剪框的坐標 [3]代表源圖大小
在touchDown的時候 先存儲左邊 然后我們要計算點的區域是 拉伸 還是移動 拉伸的話是以頂點為中心的放心
onPanDown(DragDownDetails details){ RenderBox referenceBox = context.findRenderObject(); Offset localPosition = referenceBox.globalToLocal(details.globalPosition); setState(() { if(_points.length<3){ _points.add(localPosition); _points.add(localPosition); _points.add(Offset(0, 0)); _points.add(Offset(0, 0)); } else{ _points[0]=localPosition; _points[1]=localPosition; } dHeight = cHeight; dWidth = cWidth; double radius = 20; if(hitPoint(Offset(_points[2].dx+cWidth, _points[2].dy+cHeight),radius , localPosition)){ downPosition =DownPosition.RIGHT_DOWN; isDrag = false; } else if(hitPoint(Offset(_points[2].dx+cWidth, _points[2].dy),radius , localPosition)){ downPosition =DownPosition.RIGHT_UP; isDrag = false; } else if(hitPoint(Offset(_points[2].dx, _points[2].dy+cHeight),radius , localPosition)){ downPosition =DownPosition.LEFT_DOWN; isDrag = false; } else if(hitPoint(_points[2],radius , localPosition)){ downPosition =DownPosition.LEFT_UP; isDrag = false; } }); }
移動的時候 因為 4個點的處理邏輯是不一樣的 所以需要單獨判斷 這里也做了個最小區域
onPanUpdate(DragUpdateDetails details) { RenderBox referenceBox = context.findRenderObject(); Offset localPosition = referenceBox.globalToLocal(details.globalPosition); if(isDrag){ setState(() { _points[1]=localPosition; }); } else{ setState(() { if(downPosition==DownPosition.RIGHT_DOWN){ cWidth = dWidth+localPosition.dx - _points[1].dx; cHeight = dHeight +localPosition.dy-_points[1].dy; } else if(downPosition==DownPosition.LEFT_UP){ cWidth = dWidth-(localPosition.dx - _points[1].dx); cHeight = dHeight-(localPosition.dy-_points[1].dy); _points[2]=localPosition; } else if(downPosition==DownPosition.RIGHT_UP){ cWidth = dWidth+localPosition.dx - _points[1].dx; cHeight = dHeight-(localPosition.dy-_points[1].dy); _points[2]=Offset(_points[2].dx, localPosition.dy); } else if(downPosition==DownPosition.LEFT_DOWN){ cWidth = dWidth-(localPosition.dx - _points[1].dx); cHeight = dHeight +localPosition.dy-_points[1].dy; _points[2]=Offset(localPosition.dx, _points[2].dy); } if(cWidth<20){ cWidth=20; }; if(cHeight<20){ cHeight=20; } }); } }
手指抬起的時候將一些坐標重置下
onPanEnd(DragEndDetails details){ setState(() { isDrag = true; double startX = _points[1].dx - _points[0].dx+_points[2].dx; double startY = _points[1].dy - _points[0].dy+_points[2].dy; if(startX<0) startX = 0; else if(startX+cWidth>width){ startX = width-cWidth; } if(startY<0) startY=0; else if(startY + cHeight>height){ startY = height-cHeight; } _points[0]=Offset(0, 0); _points[1]=Offset(0, 0); _points[2] = Offset(startX<0?0:startX, startY<0?0:startY); }); }