Android自定义View实现图片缩放旋转移动裁剪

Android自定义View实现图片缩放旋转移动裁剪

需求:
通过蒙版的效果,遮罩图片,然后图片可以进行随意的移动,缩放,旋转,最后通过蒙版上方的裁剪框来裁剪图片。裁剪框可以进行移动,可以通过拖动四个角的圆圈进行缩放。这里为了方便展示,直接将裁剪的图片在下方进行了展示,效果如下:
在这里插入图片描述
实现思路
1.因为要对图片进行拖拽,缩放等功能,所以不能使用自带的ImageView,而是需要自定义View。
2.通过在自定义view中重写onDraw(Canvas canvas)方法,我们把图片,遮罩层,裁剪框等绘制view中。
3.因为图片需要缩放,移动,旋转,所以我们使用Matrix这个类来处理(什么是Matrix,这里不做介绍)。
4.遮罩层我们通过计算裁剪框上下左右与view四个边的距离,然后画出遮罩层(主要就是设置遮罩层颜色)。
5.裁剪框相对简单,先画出一个矩形,然后在四个角再画四个圆圈,然后在矩形里面再画4条引导线就行。代码中各自对应一个方法。
6.为了防止裁剪框拖动或者移动时超出我们的view,我们通过检测处理,让裁剪框始终在view边缘,不超出view。

实现解析
1.因为要通过canvas在view上画裁剪框,辅助线,还有裁剪框的四个角上的圆圈,所以我们需要在构造方法中初始化画笔。

 public MoveAndScaleImageView(Context context) {
        super(context);
        init(context);
    }

    public MoveAndScaleImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }
    
private void init(Context context) {
        Paint mBmpPaint;
        mBmpPaint = new Paint();
        // 防止边缘的锯齿
        mBmpPaint.setAntiAlias(true);
        // 对位图进行滤波处理
        mBmpPaint.setFilterBitmap(true);

        // 初始化裁剪框边框的画笔
        clipRectBorderPaint = new Paint();
        clipRectBorderPaint.setStyle(Style.STROKE);
        clipRectBorderPaint.setColor(Color.parseColor("#AAFFFFFF"));//#AAFFFFFF
        clipRectBorderPaint.setStrokeWidth(6f);

        // 初始化裁剪框辅助线的画笔
        clipRectGuidelinePaint = new Paint();
        clipRectGuidelinePaint.setColor(Color.parseColor("#AAFFFFFF"));//#AAFFFFFF
        clipRectGuidelinePaint.setStrokeWidth(1f);

        // 初始化裁剪框边框四个角圆圈的画笔
        clipRectCornerPaint = new Paint();
        clipRectCornerPaint.setColor(Color.parseColor("#AAFFFFFF"));

        // 初始化整个View遮罩层的画笔
        maskLayoutPaint = new Paint();
        maskLayoutPaint.setColor(Color.parseColor("#AAFFFFFF"));
        maskLayoutPaint.setAlpha(150);
    }

2.初始化完成后,我们来看一下我们的onDraw方法,内容很简单,就是我们在移动或者缩放等操作后,根据图片,裁剪框的位置,宽高等信息,画在view中。

@Override
    protected void onDraw(Canvas canvas) {
     // 获取自定义view宽高,设置第一次绘图是裁剪框和图片在中心显示。
     // 如果是通过intent打开相册选择图片,这个地方需要自行修改,就不能使用这个判断了,需要把下面的几个方法放到其他的位置
        if(isFirstDraw) {
            setViewRectF();
            setClipRectDefaultPosition();
            setPictureDefaultPosition();
            isFirstDraw = false;
        }
        if (mImagePath != null) {
            // 画原图
            canvas.drawBitmap(mBmpToCrop, matrix, null);
            if(!isClip) {
                // 画裁剪框
                canvas.drawRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, clipRectBorderPaint);
                 // 画裁剪框4个角上的圆圈
                draw4RoundCorner(canvas);
                // 画裁剪框的辅助线
                drawGuideLines(canvas);
                // 画遮罩层
                drawMaskLayer(canvas);
            }
        }
    }

注意:上面代码的isDraw
3.上面说到onDraw就是根据我们移动图片,裁剪框等操作后的一些位置和宽高的数据,然后进行绘制。那么移动,缩放等操作,是如何扑捉到的,有事如何处理的,就是通过冲下下面的方法实现的

@Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction() & MotionEvent.ACTION_MASK){
            // 手指按下
            case MotionEvent.ACTION_DOWN:
                mood = DRAG;

                // 手指按下的点
                startPoint.set(event.getX(), event.getY());
                lastPoint.set(event.getX(),event.getY());

                getParent().requestDisallowInterceptTouchEvent(true);
                touchPosition = detectTouchPosition(event.getX(), event.getY());

                if(touchPosition == POS_OUT_OF_CLIP_RECT ) {
                    currentMatrix.set(matrix);
                }

                break;
            // 手指进行移动
            case MotionEvent.ACTION_MOVE :
                if (mood == DRAG){
                    if(touchPosition == POS_OUT_OF_CLIP_RECT) {
                        moveImage(event);
                    } else {
                        moveOrChangeClipRect(event);
                    }
                }else if (mood == ZOOM){
                    float twoFingerDistanceAfterZoom = calculateFingersSlideDistance(event);
                    if (twoFingerDistanceAfterZoom > 10f) {
                        // 缩放比例
                        float scale = twoFingerDistanceAfterZoom / twoFingerDistanceBeforeZoom;

                        matrix.set(currentMatrix);
                        matrix.postScale(scale, scale, centerPointForZoom.x, centerPointForZoom.y);
                    }
                }

                lastPoint.set(event.getX(),event.getY());
                break;
            // 手指抬起
            case MotionEvent.ACTION_UP:
                mood = NONE;
                break;
            case MotionEvent.ACTION_POINTER_UP:
                mood = NONE;
                break;
            // 屏幕上已经有一根手指,再放下一根
            case MotionEvent.ACTION_POINTER_DOWN:
                mood = ZOOM;
                twoFingerDistanceBeforeZoom = calculateFingersSlideDistance(event);
                if (twoFingerDistanceBeforeZoom > 10f) {
                    centerPointForZoom = calculateCenterPointForZoom(event);
                    currentMatrix.set(matrix);
                }
                break;
        }
        // 调用 onDraw方法
        invalidate();
        // 这里一定要是return true 不然也是无效的
        return true;
    }

下面献上自定义view的全部代码,关于其他的布局文件,activity等文件,请到git自行下载查看。项目地址在文章结尾处。

@SuppressLint("AppCompatCustomView")
public class CorpToView extends ImageView {
    /**
     * 按下的点不在裁剪框上
     */
    private static final int POS_OUT_OF_CLIP_RECT = -1;
    private static final int POS_TOP_LEFT = 0;
    private static final int POS_TOP_RIGHT = 1;
    private static final int POS_BOTTOM_LEFT = 2;
    private static final int POS_BOTTOM_RIGHT = 3;
    private static final int POS_TOP = 4;
    private static final int POS_BOTTOM = 5;
    private static final int POS_LEFT = 6;
    private static final int POS_RIGHT = 7;

    /**
     * 拖拽的是剪裁框里面
     */
    private static final int POS_CENTER = 8;
    private static final float BORDER_CORNER_LENGTH = 30f;
    private static final float TOUCH_FIELD = 10f;

    /**
     * 当前裁剪框是拖拽还是缩放
     */
    private int mood = NONE;

    /**
     * 裁剪框既不拖拽也不缩放
     */
    private static final int NONE = 0;
    /**
     * 拖拽裁剪框
     */
    private static final int DRAG = 1;
    /**
     * 缩放裁剪框
     */
    private static final int ZOOM = 2;

    private Matrix matrix = new Matrix();
    private Matrix currentMatrix = new Matrix();

    /**
     * 手指最开始按下时的点的坐标
     */
    private PointF startPoint = new PointF();
    private PointF lastPoint = new PointF();

    private PointF centerPointForZoom;

    private float twoFingerDistanceBeforeZoom;

    /**
     * 放置图片的容器View
     */
    private RectF viewRectF;

    /**
     * 要裁剪的原图的路径
     */
    private String mImagePath;

    /**
     * 存放图片的Bitmap,后面所有的图片的操作,都市通过这个对象
     */
    private Bitmap mBmpToCrop;

    /**
     * 绘制图片上面蒙版的画笔
     */
    private Paint maskLayoutPaint;

    /**
     * 裁剪框位置
     */
    private RectF clipRect;
    
    /**
     * 九宫图裁剪区外边框
     */
    private Paint clipRectBorderPaint;

    /**
     * 四个角小圆圈
     */
    private Paint clipRectCornerPaint;

    /**
     *裁剪框4条边框画笔
     */
    private Paint clipRectGuidelinePaint;

    private int touchPosition;

    /**
     * 是否点击了裁剪按钮
     */
    private boolean isClip = false;

    /**
     * 只画一次,初始化view中图片,裁剪框等的位置
     */
    private boolean isFirstDraw = true;

    public CorpToView(Context context) {
        super(context);
        init(context);
    }

    public CorpToView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    private void init(Context context) {
        Paint mBmpPaint;
        mBmpPaint = new Paint();
        // 防止边缘的锯齿
        mBmpPaint.setAntiAlias(true);
        // 对位图进行滤波处理
        mBmpPaint.setFilterBitmap(true);

        // 初始化裁剪框边框的画笔
        clipRectBorderPaint = new Paint();
        clipRectBorderPaint.setStyle(Style.STROKE);
        clipRectBorderPaint.setColor(Color.parseColor("#AAFFFFFF"));//#AAFFFFFF
        clipRectBorderPaint.setStrokeWidth(6f);

        // 初始化裁剪框辅助线的画笔
        clipRectGuidelinePaint = new Paint();
        clipRectGuidelinePaint.setColor(Color.parseColor("#AAFFFFFF"));//#AAFFFFFF
        clipRectGuidelinePaint.setStrokeWidth(1f);

        // 初始化裁剪框边框四个角圆圈的画笔
        clipRectCornerPaint = new Paint();
        clipRectCornerPaint.setColor(Color.parseColor("#AAFFFFFF"));

        // 初始化整个View遮罩层的画笔
        maskLayoutPaint = new Paint();
        maskLayoutPaint.setColor(Color.parseColor("#AAFFFFFF"));
        maskLayoutPaint.setAlpha(150);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        // 获取自定义view宽高,设置第一次绘图是裁剪框和图片在中心显示。
        // 如果是通过intent打开相册选择图片,这个地方需要自行修改,就不能使用这个判断了,需要把下面的几个方法放到其他的位置
        if(isFirstDraw) {
            setViewRectF();
            setClipRectDefaultPosition();
            setPictureDefaultPosition();
            isFirstDraw = false;
        }

        // 有图片才画
        if (mImagePath != null) {
            // 画原图
            canvas.drawBitmap(mBmpToCrop, matrix, null);
            if(!isClip) {
                // 画裁剪框
                canvas.drawRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, clipRectBorderPaint);
                // 画裁剪框4个角上的圆圈
                draw4RoundCorner(canvas);
                // 画裁剪框的辅助线
                drawGuideLines(canvas);
                // 画遮罩层
                drawMaskLayer(canvas);
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction() & MotionEvent.ACTION_MASK){
            // 手指按下
            case MotionEvent.ACTION_DOWN:
                mood = DRAG;

                // 手指按下的点
                startPoint.set(event.getX(), event.getY());
                lastPoint.set(event.getX(),event.getY());

                getParent().requestDisallowInterceptTouchEvent(true);
                touchPosition = detectTouchPosition(event.getX(), event.getY());

                if(touchPosition == POS_OUT_OF_CLIP_RECT ) {
                    currentMatrix.set(matrix);
                }

                break;
            // 手指进行移动
            case MotionEvent.ACTION_MOVE :
                if (mood == DRAG){
                    if(touchPosition == POS_OUT_OF_CLIP_RECT) {
                        moveImage(event);
                    } else {
                        moveOrChangeClipRect(event);
                    }
                }else if (mood == ZOOM){
                    float twoFingerDistanceAfterZoom = calculateFingersSlideDistance(event);
                    if (twoFingerDistanceAfterZoom > 10f) {
                        // 缩放比例
                        float scale = twoFingerDistanceAfterZoom / twoFingerDistanceBeforeZoom;

                        matrix.set(currentMatrix);
                        matrix.postScale(scale, scale, centerPointForZoom.x, centerPointForZoom.y);
                    }
                }

                lastPoint.set(event.getX(),event.getY());
                break;
            // 手指抬起
            case MotionEvent.ACTION_UP:
                mood = NONE;
                break;
            case MotionEvent.ACTION_POINTER_UP:
                mood = NONE;
                break;
            // 屏幕上已经有一根手指,再放下一根
            case MotionEvent.ACTION_POINTER_DOWN:
                mood = ZOOM;
                twoFingerDistanceBeforeZoom = calculateFingersSlideDistance(event);
                if (twoFingerDistanceBeforeZoom > 10f) {
                    centerPointForZoom = calculateCenterPointForZoom(event);
                    currentMatrix.set(matrix);
                }
                break;
        }
        // 调用 onDraw方法
        invalidate();
        // 这里一定要是return true 不然也是无效的
        return true;
    }

    /**
     * 在View中显示原图
     * @param picPath 原图的路径
     */
    public void showImage(String picPath) {
        this.mImagePath = picPath;
        mBmpToCrop = BitmapFactory.decodeFile(mImagePath);
        invalidate();
    }

    /**
     * 让图片旋转90度
     */
    public void rotate90(){
        matrix.preRotate(90,mBmpToCrop.getWidth()/2,mBmpToCrop.getHeight()/2);
        invalidate();
    }

    private void setViewRectF() {
        viewRectF = new RectF();
        viewRectF.left = 0;
        viewRectF.top = 0;
        viewRectF.right =  getWidth();
        viewRectF.bottom = getHeight();
    }

    /**
     * 设置裁剪框默认的大小和在view上的位置
     */
    private void setClipRectDefaultPosition() {
        // 裁剪框默任宽高
        final float CLIP_RECT_WIDTH = 200f;
        final float CLIP_RECT_HEIGHT = 200f;

        // 使裁剪框一开始出现在图片的中心位置
        clipRect = new RectF();
        clipRect.left = (viewRectF.width() - CLIP_RECT_WIDTH) / 2;
        clipRect.top = (viewRectF.height() - CLIP_RECT_HEIGHT) / 2;
        clipRect.right = clipRect.left + CLIP_RECT_WIDTH;;
        clipRect.bottom = clipRect.top + CLIP_RECT_HEIGHT;

    }
    /**
     * 显示原图时,设置图片显示在view中的位置
     */
    private void setPictureDefaultPosition () {
        float dx = 0;
        float dy = 0;

        if(mBmpToCrop.getWidth() < viewRectF.width()) {
            dx = (viewRectF.width() - mBmpToCrop.getWidth()) / 2;
        }

        if(mBmpToCrop.getHeight() < viewRectF.height()) {
            dy = (viewRectF.height() - mBmpToCrop.getHeight()) / 2;
        }

        // 平移缩放模式,相对于当前位置,移动多少距离
        matrix.postTranslate(dx,dy);

    }
    /**
     * 获取裁剪框区域的图片
     * @return
     */
    public Bitmap getClipRectImage() {
        isClip = true;
        destroyDrawingCache();
        setDrawingCacheEnabled(true);
        buildDrawingCache();
        Bitmap mBitmap  = getDrawingCache();
        isClip = false;
        return Bitmap.createBitmap(mBitmap, (int) clipRect.left, (int) clipRect.top, (int) clipRect.width(), (int) clipRect.height());
    }


    /**
     * 自测用,在自定义view中显示裁剪的图片,覆盖之前的图片。可以忽略此方法
     */
    public void showCilpRectImage() {

        isClip = true;
        destroyDrawingCache();
        setDrawingCacheEnabled(true);
        buildDrawingCache();
        Bitmap mBitmap  = getDrawingCache();

        mBmpToCrop =Bitmap.createBitmap(mBitmap, (int) clipRect.left, (int) clipRect.top, (int) clipRect.width(), (int) clipRect.height());
        matrix = new Matrix();
        isClip = false;
        invalidate();
    }

    /**
     * 拖拽图片是,移动图片
     * @param event
     */
    private void moveImage (MotionEvent event) {
        // 图片要移动的距离
        float dx = event.getX() - startPoint.x;
        float dy = event.getY() - startPoint.y;

        // 平移缩放模式,相对于当前位置,移动多少距离
        matrix.set(currentMatrix);
        matrix.postTranslate(dx,dy);
    }

    /**
     * 移动裁剪框或者改变裁剪框大小
     * @param event
     */
    private void moveOrChangeClipRect(MotionEvent event) {
        float deltaX = event.getX() - lastPoint.x;
        float deltaY = event.getY() - lastPoint.y;

        switch (touchPosition) {
            case POS_CENTER:
               moveWholeClipRect(deltaX,deltaY);
                break;
            case POS_TOP:
                changeClipRectTop(deltaY);
                break;
            case POS_BOTTOM:
                changeClipRectBottom(deltaY);
                break;
            case POS_LEFT:
                changeClipRectLeft(deltaX);
                break;
            case POS_RIGHT:
                changeClipRectRight(deltaX);
                break;
            case POS_TOP_LEFT:
                changeClipRectTop(deltaY);
                changeClipRectLeft(deltaX);
                break;
            case POS_TOP_RIGHT:
                changeClipRectTop(deltaY);
                changeClipRectRight(deltaX);
                break;
            case POS_BOTTOM_LEFT:
                changeClipRectBottom(deltaY);
                changeClipRectLeft(deltaX);
                break;
            case POS_BOTTOM_RIGHT:
                changeClipRectBottom(deltaY);
                changeClipRectRight(deltaX);
                break;
            default:

                break;
        }
    }

    /**
     * 获取缩放时的中心位置
     */
    private PointF calculateCenterPointForZoom(MotionEvent event) {
        float midx = event.getX(1) + event.getX(0);
        float midy = event.getY(1) + event.getY(0);
        return new PointF(midx/2,midy/2);
    }

    /**
     * 计算手指滑动距离
     * @param event
     * @return
     */
    private float calculateFingersSlideDistance(MotionEvent event) {
        float dx = event.getX(1) - event.getX(0);
        float dy = event.getY(1) - event.getY(0);
        return (float)Math.sqrt(dx * dx + dy * dy);
    }

    /**
     * 绘制剪切的框四周半透明的遮罩层
     * @param canvas
     */
    private void drawMaskLayer(Canvas canvas) {

        /*-
          -------------------------------------
          |              遮罩层top             |
          -------------------------------------
          |  遮  |                     |  遮   |
          |  罩  |                     |  罩   |
          |  层  |                     |  层   |
          | left |        可见层       | right |
          |      |                    |       |
          -------------------------------------
          |            遮罩层bottom            |
          -------------------------------------
         */

        PointF p1 = new PointF();
        PointF p2 = new PointF();

        // 上阴影
        p1.set(0,0);
        p2.set(viewRectF.width(),clipRect.top);
        canvas.drawRect(p1.x,p1.y,p2.x,p2.y, maskLayoutPaint);

        // 下阴影
        p1.set(0,clipRect.bottom);
        p2.set(viewRectF.width(),viewRectF.height());
        canvas.drawRect(p1.x,p1.y,p2.x,p2.y, maskLayoutPaint);

        // 左阴影
        p1.set(0,clipRect.top);
        p2.set(clipRect.left,clipRect.bottom);
        canvas.drawRect(p1.x,p1.y,p2.x,p2.y, maskLayoutPaint);

        //右阴影
        p1.set(clipRect.right,clipRect.top);
        p2.set(viewRectF.width(),clipRect.bottom);
        canvas.drawRect(p1.x,p1.y,p2.x,p2.y, maskLayoutPaint);
    }

    /**
     * 画裁剪区域中间的参考线
     * @param canvas
     */
    private void drawGuideLines(Canvas canvas) {
        // Draw vertical guidelines.
        final float oneThirdCropWidth = clipRect.width() / 3;

        final float x1 = clipRect.left + oneThirdCropWidth;
        canvas.drawLine(x1, clipRect.top, x1, clipRect.bottom, clipRectGuidelinePaint);
        final float x2 = clipRect.right - oneThirdCropWidth;
        canvas.drawLine(x2, clipRect.top, x2, clipRect.bottom, clipRectGuidelinePaint);

        // Draw horizontal guidelines.
        final float oneThirdCropHeight = clipRect.height() / 3;

        final float y1 = clipRect.top + oneThirdCropHeight;
        canvas.drawLine(clipRect.left, y1, clipRect.right, y1, clipRectGuidelinePaint);
        final float y2 = clipRect.bottom - oneThirdCropHeight;
        canvas.drawLine(clipRect.left, y2, clipRect.right, y2, clipRectGuidelinePaint);
    }

    /**
     * 裁剪框四个角的圆圈
     * @param canvas
     */
    private void draw4RoundCorner(Canvas canvas) {
        canvas.drawCircle(clipRect.left,clipRect.top,12,clipRectCornerPaint);
        canvas.drawCircle(clipRect.right,clipRect.top,12,clipRectCornerPaint);
        canvas.drawCircle(clipRect.left,clipRect.bottom,12,clipRectCornerPaint);
        canvas.drawCircle(clipRect.right,clipRect.bottom,12,clipRectCornerPaint);
    }

    /**
     * 检测按下触碰的点在裁剪框上的哪个位置上,或者没在裁剪框上
     * @param x
     * @param y
     * @return
     */
    private int detectTouchPosition(float x, float y) {
        if (x > clipRect.left + TOUCH_FIELD && x < clipRect.right - TOUCH_FIELD
                && y > clipRect.top + TOUCH_FIELD && y < clipRect.bottom - TOUCH_FIELD)
            return POS_CENTER;

        if (x > clipRect.left + BORDER_CORNER_LENGTH && x < clipRect.right - BORDER_CORNER_LENGTH) {
            if (y > clipRect.top - TOUCH_FIELD && y < clipRect.top + TOUCH_FIELD)
                return POS_TOP;
            if (y > clipRect.bottom - TOUCH_FIELD && y < clipRect.bottom + TOUCH_FIELD)
                return POS_BOTTOM;
        }

        if (y > clipRect.top + BORDER_CORNER_LENGTH && y < clipRect.bottom - BORDER_CORNER_LENGTH) {
            if (x > clipRect.left - TOUCH_FIELD && x < clipRect.left + TOUCH_FIELD)
                return POS_LEFT;
            if (x > clipRect.right - TOUCH_FIELD && x < clipRect.right + TOUCH_FIELD)
                return POS_RIGHT;
        }

        // 前面的逻辑已经排除掉了几种情况 所以后面的 ┏ ┓ ┗ ┛ 边角就按照所占区域的方形来判断就可以了
        if (x > clipRect.left - TOUCH_FIELD && x < clipRect.left + BORDER_CORNER_LENGTH) {
            if (y > clipRect.top - TOUCH_FIELD && y < clipRect.top + BORDER_CORNER_LENGTH)
                return POS_TOP_LEFT;
            if (y > clipRect.bottom - BORDER_CORNER_LENGTH && y < clipRect.bottom + TOUCH_FIELD)
                return POS_BOTTOM_LEFT;
        }

        if (x > clipRect.right - BORDER_CORNER_LENGTH && x < clipRect.right + TOUCH_FIELD) {
            if (y > clipRect.top - TOUCH_FIELD && y < clipRect.top + BORDER_CORNER_LENGTH)
                return POS_TOP_RIGHT;
            if (y > clipRect.bottom - BORDER_CORNER_LENGTH && y < clipRect.bottom + TOUCH_FIELD)
                return POS_BOTTOM_RIGHT;
        }

        return POS_OUT_OF_CLIP_RECT;
    }

    /**
     * 改变裁剪框左边框与view左边框的距离
     * @param delta
     */
    private void changeClipRectLeft(float delta) {
        clipRect.left += delta;
        preventClipRectLeftOverView();
    }

    /**
     * 不改变大小,移动裁剪框位置
     * @param deltaX
     * @param deltaY
     */
    private void moveWholeClipRect(float deltaX,float deltaY) {

        float width = clipRect.width();
        float height = clipRect.height();

        clipRect.left += deltaX;

        if (clipRect.left < viewRectF.left) {
            clipRect.left = viewRectF.left;
        }

        if (clipRect.left > viewRectF.right - clipRect.width()) {
            clipRect.left = viewRectF.right - clipRect.width();
        }

        clipRect.top += deltaY;
        if (clipRect.top < viewRectF.top) {
            clipRect.top = viewRectF.top;
        }

        if (clipRect.top > viewRectF.bottom - clipRect.height()) {
            clipRect.top = viewRectF.bottom - clipRect.height();
        }

        clipRect.right = clipRect.left + width;
        clipRect.bottom = clipRect.top + height;
    }

    /**
     * 改变裁剪框上边框与view上边框的距离
     * @param delta
     */
    private void changeClipRectTop(float delta) {
        clipRect.top += delta;
        preventClipRectTopOverView();
    }

    /**
     * 改变裁剪框右边框与view右边框的距离
     * @param delta
     */
    private void changeClipRectRight(float delta) {
        clipRect.right += delta;
        preventClipRectRightOverView();

    }

    /**
     * 改变裁剪框下边框与view下边框的距离
     * @param delta
     */
    private void changeClipRectBottom(float delta) {
        clipRect.bottom += delta;
        preventClipRectBottomOverView();
    }

    /**
     * 防止裁剪框左侧超出View
     */
    private void preventClipRectLeftOverView() {
        if (clipRect.left < viewRectF.left) {
            clipRect.left = viewRectF.left;
        }

        if (clipRect.width() < 2 * BORDER_CORNER_LENGTH) {
            clipRect.left = clipRect.right - 2 * BORDER_CORNER_LENGTH;
        }
    }

    /**
     * 防止裁剪框顶部超出View
     */
    private void preventClipRectTopOverView() {
        if (clipRect.top < viewRectF.top) {
            clipRect.top = viewRectF.top;
        }

        if (clipRect.height() < 2 * BORDER_CORNER_LENGTH) {
            clipRect.top = clipRect.bottom - 2 * BORDER_CORNER_LENGTH;
        }
    }

    /**
     * 防止裁剪框右侧超出View
     */
    private void preventClipRectRightOverView() {
        if (clipRect.right > viewRectF.right){
            clipRect.right = viewRectF.right;
        }

        if (clipRect.width() < 2 * BORDER_CORNER_LENGTH) {
            clipRect.right = clipRect.left + 2 * BORDER_CORNER_LENGTH;
        }
    }

    /**
     * 防止裁剪框底部超出View
     */
    private void preventClipRectBottomOverView() {
        if (clipRect.bottom > viewRectF.bottom) {
            clipRect.bottom = viewRectF.bottom;
        }

        if (clipRect.height() < 2 * BORDER_CORNER_LENGTH) {
            clipRect.bottom = clipRect.top + 2 * BORDER_CORNER_LENGTH;
        }
    }
}

最后请注意,项目中通过使用implementation 'me.jessyan:autosize:1.1.2’来实现自适应,所以在AndroidManifest.xml中添加了

 <meta-data
            android:name="design_width_in_dp"
            android:value="360" />
        <meta-data
            android:name="design_height_in_dp"
            android:value="640" />

请不要漏掉。这个meta-data的意思是,我的UI设计是在360*640设计的UI,然后当我们使用其他分辨率的手机时,会根据我的这个设置为基础,进行自动适配,对布局进行缩放。具体可【百度今日头条屏幕适配方案终极版 AndroidAutoSize】了解详情

项目地址:
github:https://github.com/GitHubProfessor/croptoview
码云:https://gitee.com/kyle_lhb/croptoview

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值