自定义裁剪图片控件

先看效果:

代码:

package com.ytmfdw.imageview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;

/**
 * 自定义裁剪图片控件
 */
public class MyImageView extends ImageView {

    //双击回调接口
    public interface OnDoubleClickListener {
        public void getBitmap(Bitmap bitmap);
    }

    static final String TAG = "ytmfdw";

    private static final int MIN_FRAME_WIDTH = 50; // originally 240
    private static final int MIN_FRAME_HEIGHT = 20; // originally 240
    private static final int MAX_FRAME_WIDTH = 800; // originally 480
    private static final int MAX_FRAME_HEIGHT = 600; // originally 360

    private Rect framingRect;
    private Point screenResolution;
    private final Paint paint;

    private final int maskColor;
    private final int frameColor;
    private final int cornerColor;

    private boolean initialized;
    private long lastUpTime = 0;

    /**
     * 是否平移
     */
    private boolean isTranslate = false;

    private OnDoubleClickListener clickListener;

    public MyImageView(Context context) {
        this(context, null);
    }

    public MyImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        maskColor = Color.parseColor("#60000000");
        frameColor = Color.parseColor("#ffd6d6d6");
        cornerColor = Color.parseColor("#ffffffff");
//        maskColor = getResources().getColor(R.color.viewfinder_mask);
//        frameColor = getResources().getColor(R.color.viewfinder_frame);
//        cornerColor = getResources().getColor(R.color.viewfinder_corners);
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        init();
    }

    /**
     * 设置监听
     *
     * @param listener
     */
    public void setDoubleClickListener(OnDoubleClickListener listener) {
        clickListener = listener;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = getMeasuredWidth();
        int height = getMeasuredHeight();
        screenResolution = new Point(width, height);
    }

    /**
     * 初始化
     */
    private void init() {

        int width = getResources().getDisplayMetrics().widthPixels;
        int height = getResources().getDisplayMetrics().heightPixels;
        screenResolution = new Point(width, height);

        setOnTouchListener(new View.OnTouchListener() {
            int lastX = -1;
            int lastY = -1;

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        lastX = -1;
                        lastY = -1;
                        return true;
                    case MotionEvent.ACTION_MOVE:
                        int currentX = (int) event.getX();
                        int currentY = (int) event.getY();

                        try {
                            Rect rect = getFramingRect();

                            final int BUFFER = 50;
                            final int BIG_BUFFER = 60;
                            if (lastX >= 0) {
                                // Adjust the size of the viewfinder rectangle. Check if the touch event occurs in the corner areas first, because the regions overlap.
                                if (((currentX >= rect.left - BIG_BUFFER && currentX <= rect.left + BIG_BUFFER) || (lastX >= rect.left - BIG_BUFFER && lastX <= rect.left + BIG_BUFFER))
                                        && ((currentY <= rect.top + BIG_BUFFER && currentY >= rect.top - BIG_BUFFER) || (lastY <= rect.top + BIG_BUFFER && lastY >= rect.top - BIG_BUFFER))) {
                                    // Top left corner: adjust both top and left sides
                                    adjustFramingRect(2 * (lastX - currentX), 2 * (lastY - currentY));
                                } else if (((currentX >= rect.right - BIG_BUFFER && currentX <= rect.right + BIG_BUFFER) || (lastX >= rect.right - BIG_BUFFER && lastX <= rect.right + BIG_BUFFER))
                                        && ((currentY <= rect.top + BIG_BUFFER && currentY >= rect.top - BIG_BUFFER) || (lastY <= rect.top + BIG_BUFFER && lastY >= rect.top - BIG_BUFFER))) {
                                    // Top right corner: adjust both top and right sides
                                    adjustFramingRect(2 * (currentX - lastX), 2 * (lastY - currentY));
                                } else if (((currentX >= rect.left - BIG_BUFFER && currentX <= rect.left + BIG_BUFFER) || (lastX >= rect.left - BIG_BUFFER && lastX <= rect.left + BIG_BUFFER))
                                        && ((currentY <= rect.bottom + BIG_BUFFER && currentY >= rect.bottom - BIG_BUFFER) || (lastY <= rect.bottom + BIG_BUFFER && lastY >= rect.bottom - BIG_BUFFER))) {
                                    // Bottom left corner: adjust both bottom and left sides
                                    adjustFramingRect(2 * (lastX - currentX), 2 * (currentY - lastY));
                                } else if (((currentX >= rect.right - BIG_BUFFER && currentX <= rect.right + BIG_BUFFER) || (lastX >= rect.right - BIG_BUFFER && lastX <= rect.right + BIG_BUFFER))
                                        && ((currentY <= rect.bottom + BIG_BUFFER && currentY >= rect.bottom - BIG_BUFFER) || (lastY <= rect.bottom + BIG_BUFFER && lastY >= rect.bottom - BIG_BUFFER))) {
                                    // Bottom right corner: adjust both bottom and right sides
                                    adjustFramingRect(2 * (currentX - lastX), 2 * (currentY - lastY));
                                } else if (((currentX >= rect.left - BUFFER && currentX <= rect.left + BUFFER) || (lastX >= rect.left - BUFFER && lastX <= rect.left + BUFFER))
                                        && ((currentY <= rect.bottom && currentY >= rect.top) || (lastY <= rect.bottom && lastY >= rect.top))) {
                                    // Adjusting left side: event falls within BUFFER pixels of left side, and between top and bottom side limits
                                    adjustFramingRect(2 * (lastX - currentX), 0);
                                } else if (((currentX >= rect.right - BUFFER && currentX <= rect.right + BUFFER) || (lastX >= rect.right - BUFFER && lastX <= rect.right + BUFFER))
                                        && ((currentY <= rect.bottom && currentY >= rect.top) || (lastY <= rect.bottom && lastY >= rect.top))) {
                                    // Adjusting right side: event falls within BUFFER pixels of right side, and between top and bottom side limits
                                    adjustFramingRect(2 * (currentX - lastX), 0);
                                } else if (((currentY <= rect.top + BUFFER && currentY >= rect.top - BUFFER) || (lastY <= rect.top + BUFFER && lastY >= rect.top - BUFFER))
                                        && ((currentX <= rect.right && currentX >= rect.left) || (lastX <= rect.right && lastX >= rect.left))) {
                                    // Adjusting top side: event falls within BUFFER pixels of top side, and between left and right side limits
                                    adjustFramingRect(0, 2 * (lastY - currentY));
                                } else if (((currentY <= rect.bottom + BUFFER && currentY >= rect.bottom - BUFFER) || (lastY <= rect.bottom + BUFFER && lastY >= rect.bottom - BUFFER))
                                        && ((currentX <= rect.right && currentX >= rect.left) || (lastX <= rect.right && lastX >= rect.left))) {
                                    // Adjusting bottom side: event falls within BUFFER pixels of bottom side, and between left and right side limits
                                    adjustFramingRect(0, 2 * (currentY - lastY));
                                } else if (currentX > rect.left && currentX < (rect.left + rect.width()) && currentY > rect.top && currentY < (rect.top + rect.height())) {
                                    //平移,当在框框内进行移动时,平移框框
                                    isTranslate = true;
                                    translateRect(currentX - lastX, currentY - lastY);
                                }
                            }
                        } catch (NullPointerException e) {
                            Log.e(TAG, "Framing rect not available", e);
                        }
                        v.invalidate();
                        lastX = currentX;
                        lastY = currentY;
                        return true;
                    case MotionEvent.ACTION_UP:
                        lastX = -1;
                        lastY = -1;
                        isTranslate = false;
//                        currentDx = 0;
//                        currentDy = 0;
                        //判断是否双击
                        if (System.currentTimeMillis() - lastUpTime < 300) {
                            //800毫秒内算双击
                            if (clickListener != null) {
                                Bitmap bitmap = clip();
                                clickListener.getBitmap(bitmap);
                            }
                            return true;
                        }
                        lastUpTime = System.currentTimeMillis();
                        return true;
                }
                return false;
            }
        });

        initialized = true;

    }

    /**
     * Calculates the framing rect which the UI should draw to show the user where to place the
     * barcode. This target helps with alignment as well as forces the user to hold the device
     * far enough away to ensure the image will be in focus.
     *
     * @return The rectangle to draw on screen in window coordinates.
     */
    public synchronized Rect getFramingRect() {
        if (framingRect == null) {
            if (screenResolution == null) {
                // Called early, before init even finished
                return null;
            }
            int width = screenResolution.x * 3 / 5;
            if (width < MIN_FRAME_WIDTH) {
                width = MIN_FRAME_WIDTH;
            } else if (width > MAX_FRAME_WIDTH) {
                width = MAX_FRAME_WIDTH;
            }
            int height = screenResolution.y * 1 / 5;
            if (height < MIN_FRAME_HEIGHT) {
                height = MIN_FRAME_HEIGHT;
            } else if (height > MAX_FRAME_HEIGHT) {
                height = MAX_FRAME_HEIGHT;
            }
            int leftOffset = (screenResolution.x - width) / 2;
            int topOffset = (screenResolution.y - height) / 2;
            framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height);
        }
        return framingRect;
    }

    private int currentDx = 0;
    private int currentDy = 0;

    /**
     * 平移框框
     *
     * @param dx
     * @param dy
     */
    public synchronized void translateRect(int dx, int dy) {
        Log.d(TAG, "dx=" + dx);
        Log.d(TAG, "dy=" + dy);
        if (initialized) {
            int newWidth = framingRect.width();
            int newHeight = framingRect.height();
            currentDx += dx;
            currentDy += dy;
            int leftOffset = (screenResolution.x - newWidth) / 2 + currentDx;
            int topOffset = (screenResolution.y - newHeight) / 2 + currentDy;
            if (leftOffset < 0) {
                leftOffset = 0;
            }
            if (topOffset < 0) {
                topOffset = 0;
            }
            if (leftOffset + newWidth > screenResolution.x) {
                leftOffset = screenResolution.x - newWidth;
            }
            if (topOffset + newHeight > screenResolution.y) {
                topOffset = screenResolution.y - newHeight;
            }
            framingRect = new Rect(leftOffset, topOffset, leftOffset + newWidth, topOffset + newHeight);
        }
    }

    /**
     * Changes the size of the framing rect.
     *
     * @param deltaWidth  Number of pixels to adjust the width
     * @param deltaHeight Number of pixels to adjust the height
     */
    public synchronized void adjustFramingRect(int deltaWidth, int deltaHeight) {
        if (initialized && !isTranslate) {
            // Set maximum and minimum sizes
            if ((framingRect.width() + deltaWidth > screenResolution.x - 4) || (framingRect.width() + deltaWidth < 50)) {
                deltaWidth = 0;
            }
            if ((framingRect.height() + deltaHeight > screenResolution.y - 4) || (framingRect.height() + deltaHeight < 50)) {
                deltaHeight = 0;
            }

            int newWidth = framingRect.width() + deltaWidth;
            int newHeight = framingRect.height() + deltaHeight;
            int leftOffset = (screenResolution.x - newWidth) / 2 + currentDx;
            int topOffset = (screenResolution.y - newHeight) / 2 + currentDy;
            framingRect = new Rect(leftOffset, topOffset, leftOffset + newWidth, topOffset + newHeight);
//            framingRectInPreview = null;
        } else {
//            requestedFramingRectWidth = deltaWidth;
//            requestedFramingRectHeight = deltaHeight;
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        {
            Rect frame = getFramingRect();
            if (frame == null) {
                return;
            }
            int width = canvas.getWidth();
            int height = canvas.getHeight();

            // Draw the exterior (i.e. outside the framing rect) darkened
            paint.setColor(maskColor);
            canvas.drawRect(0, 0, width, frame.top, paint);
            canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);
            canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint);
            canvas.drawRect(0, frame.bottom + 1, width, height, paint);
            // Draw a two pixel solid border inside the framing rect
            paint.setAlpha(0);
            paint.setStyle(Paint.Style.FILL);
            paint.setColor(frameColor);
            canvas.drawRect(frame.left, frame.top, frame.right + 1, frame.top + 2, paint);
            canvas.drawRect(frame.left, frame.top + 2, frame.left + 2, frame.bottom - 1, paint);
            canvas.drawRect(frame.right - 1, frame.top, frame.right + 1, frame.bottom - 1, paint);
            canvas.drawRect(frame.left, frame.bottom - 1, frame.right + 1, frame.bottom + 1, paint);

            // Draw the framing rect corner UI elements
            paint.setColor(cornerColor);
            canvas.drawRect(frame.left - 15, frame.top - 15, frame.left + 15, frame.top, paint);
            canvas.drawRect(frame.left - 15, frame.top, frame.left, frame.top + 15, paint);
            canvas.drawRect(frame.right - 15, frame.top - 15, frame.right + 15, frame.top, paint);
            canvas.drawRect(frame.right, frame.top - 15, frame.right + 15, frame.top + 15, paint);
            canvas.drawRect(frame.left - 15, frame.bottom, frame.left + 15, frame.bottom + 15, paint);
            canvas.drawRect(frame.left - 15, frame.bottom - 15, frame.left, frame.bottom, paint);
            canvas.drawRect(frame.right - 15, frame.bottom, frame.right + 15, frame.bottom + 15, paint);
            canvas.drawRect(frame.right, frame.bottom - 15, frame.right + 15, frame.bottom + 15, paint);
        }
    }


    /**
     * 剪切图片,返回剪切后的bitmap对象
     *
     * @return
     */
    public Bitmap clip() {
        Rect frame = getFramingRect();
        Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(),
                Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        draw(canvas);
        return Bitmap.createBitmap(bitmap, frame.left,
                frame.top, frame.width(),
                frame.height());
    }
}
步骤:

1、继承自ImageView,所有ImageView的相关属性都具有

2、构造方法中,进行初始化,完成:颜色、画笔、矩形框的初始化

3、在onMeasure中,计算控件的测量宽高,得到screenResolution的点,其实是保存控件的大小

4、在初始化方法中,设置onTouch监听,按下时,初始化相关数据,移动时,得到手指位置,判断是移动还是缩放,缩放调用adjustFramingRect方法 ,平移调用translate方法

5、重写onDraw方法 ,在该方法中,绘制相关矩形:首先绘制掩码矩形:四块:左上右下,得到中间空白,四周半透明的遮罩层

6、绘制四个角的白色控制柄,每个柄由两个矩形组成,总共八个

7、截图:根据 中单矩形来截,调用clip方法,得到Bitmap,在手指抬起时,记录下抬起时间,比较两次抬手时间,判断是否是双击,时间设置为300ms

完整代码下载:

csdn

github

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ytmfdw

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值