1. 程式人生 > >Flutter 實現圖片裁剪

Flutter 實現圖片裁剪

circle tps paint pos inf start null move hit

github地址

實現原理很簡單 ,自己繪制一個裁剪框, 根據手勢 選擇到適合的位置 ,然後將選中的區域繪制到一個新的圖片上,從而完成裁剪

技術分享圖片技術分享圖片技術分享圖片

裁剪框的繪制 這裏我是根據點來連線的 因為每個點上會繪制一個拉伸的標識符

      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);
    });
  }

Flutter 實現圖片裁剪