Flutter 实现图片裁剪

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

 

posted @ 2018-12-31 20:27  dikeboyR  阅读(9520)  评论(2编辑  收藏  举报