package imageselector.view; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PointF; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Xfermode; import android.support.v7.widget.AppCompatImageView; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.view.MotionEvent; import android.view.WindowManager; public class ClipImageView extends AppCompatImageView { private PointF mDownPoint; private PointF mMiddlePoint; private Matrix mMatrix; private Matrix mTempMatrix; private int mBitmapWidth; private int mBitmapHeight; private final int MODE_NONE = 0; private final int MODE_DRAG = 1; private final int MODE_ZOOM = 2; private final int MODE_POINTER_UP = 3; private int CURR_MODE = MODE_NONE; private float mLastDistance; private Paint mFrontGroundPaint = new Paint(); private int mTargetWidth; private int mTargetHeight; private Xfermode mXfermode; private Rect r; private RectF rf; private float mCircleCenterX, mCircleCenterY; private float mCircleX, mCircleY; private boolean isCutImage; public ClipImageView(Context context) { super(context); setRadius(); } public ClipImageView(Context context, AttributeSet attrs) { super(context, attrs); setRadius(); } /** * 设置要剪裁的图片 * * @param bitmap */ public void setBitmapData(Bitmap bitmap) { if (bitmap == null) { return; } mBitmapHeight = bitmap.getHeight(); mBitmapWidth = bitmap.getWidth(); setImageBitmap(bitmap); init(); } private void init() { mDownPoint = new PointF(); mMiddlePoint = new PointF(); mMatrix = new Matrix(); mTempMatrix = new Matrix(); mFrontGroundPaint.setColor(Color.parseColor("#ac000000")); mFrontGroundPaint.setAntiAlias(true); mXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT); setScaleType(ScaleType.MATRIX); post(new Runnable() { @Override public void run() { center(); } }); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); mCircleCenterX = getWidth() / 2; mCircleCenterY = getHeight() / 2; mCircleX = mCircleCenterX - mTargetWidth / 2; mCircleY = mCircleCenterY - mTargetHeight / 2; } private void setRadius() { int width = getScreenWidth(getContext()); int height = getScreenHeight(getContext()); if (width > height) { mTargetWidth = height; mTargetHeight = height; } else { mTargetWidth = width; mTargetHeight = width; } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (isCutImage) { return; } if (rf == null || rf.isEmpty()) { r = new Rect(0, 0, getWidth(), getHeight()); rf = new RectF(r); } // 画入前景圆形蒙板层 int sc = canvas.saveLayer(rf, null, Canvas.ALL_SAVE_FLAG); //画入矩形黑色半透明蒙板层 canvas.drawRect(r, mFrontGroundPaint); //设置Xfermode,目的是为了去除矩形黑色半透明蒙板层和圆形的相交部分 mFrontGroundPaint.setXfermode(mXfermode); //画入正方形 canvas.drawRect(mCircleCenterX - mTargetWidth / 2, mCircleCenterY - mTargetHeight / 2, mCircleCenterX + mTargetWidth / 2, mCircleCenterY + mTargetHeight / 2, mFrontGroundPaint); canvas.restoreToCount(sc); //清除Xfermode,防止影响下次画图 mFrontGroundPaint.setXfermode(null); } /** * 截取Bitmap * * @return */ public Bitmap clipImage() { isCutImage = true; Paint paint = new Paint(); setDrawingCacheEnabled(true); Bitmap bitmap = getDrawingCache(); Bitmap targetBitmap = Bitmap.createBitmap(mTargetWidth, mTargetHeight, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(targetBitmap); RectF dst = new RectF(-bitmap.getWidth() / 2 + mTargetWidth / 2, -getHeight() / 2 + mTargetHeight / 2, bitmap.getWidth() / 2 + mTargetWidth / 2, getHeight() / 2 + mTargetHeight / 2); canvas.drawBitmap(bitmap, null, dst, paint); setDrawingCacheEnabled(false); bitmap.recycle(); bitmap = null; isCutImage = false; //返回正方形图片 return targetBitmap; } @Override public boolean onTouchEvent(MotionEvent event) { if (mMatrix == null) { return super.onTouchEvent(event); } float[] values = new float[9]; mMatrix.getValues(values); float left = values[Matrix.MTRANS_X]; float top = values[Matrix.MTRANS_Y]; float right = (left + mBitmapWidth * values[Matrix.MSCALE_X]); float bottom = (top + mBitmapHeight * values[Matrix.MSCALE_Y]); float x = 0f; float y = 0f; switch (event.getAction() & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: CURR_MODE = MODE_DRAG; mDownPoint.set(event.getX(), event.getY()); break; case MotionEvent.ACTION_POINTER_DOWN: if (getDistance(event) > 10f) { CURR_MODE = MODE_ZOOM; midPoint(mMiddlePoint, event); mLastDistance = getDistance(event); } break; case MotionEvent.ACTION_MOVE: //如果当前模式为拖曳(单指触屏) if (CURR_MODE == MODE_DRAG || CURR_MODE == MODE_POINTER_UP) { if (CURR_MODE == MODE_DRAG) { x = event.getX() - mDownPoint.x; y = event.getY() - mDownPoint.y; //left靠边 if (x + left > mCircleX) { x = 0; } //right靠边 if (x + right < mCircleX + mTargetWidth) { x = 0; } //top靠边 if (y + top > mCircleY) { y = 0; } //bottom靠边 if (y + bottom < mCircleY + mTargetHeight) { y = 0; } mMatrix.postTranslate(x, y); mDownPoint.set(event.getX(), event.getY()); } else { CURR_MODE = MODE_DRAG; mDownPoint.set(event.getX(), event.getY()); } } else { //否则当前模式为缩放(双指触屏) float distance = getDistance(event); if (distance > 10f) { float scale = distance / mLastDistance; //left靠边 if (left >= mCircleX) { mMiddlePoint.x = 0; } //right靠边 if (right <= mCircleX + mTargetWidth) { mMiddlePoint.x = right; } //top靠边 if (top >= mCircleY) { mMiddlePoint.y = 0; } //bottom靠边 if (bottom <= mCircleY + mTargetHeight) { mMiddlePoint.y = bottom; } mTempMatrix.set(mMatrix); mTempMatrix.postScale(scale, scale, mMiddlePoint.x, mMiddlePoint.y); float[] temp_values = new float[9]; mTempMatrix.getValues(temp_values); float temp_left = temp_values[Matrix.MTRANS_X]; float temp_top = temp_values[Matrix.MTRANS_Y]; float temp_right = (temp_left + mBitmapWidth * temp_values[Matrix.MSCALE_X]); float temp_bottom = (temp_top + mBitmapHeight * temp_values[Matrix.MSCALE_Y]); //靠边预判断 if (temp_left > mCircleX || temp_right < mCircleX + mTargetWidth || temp_top > mCircleY || temp_bottom < mCircleY + mTargetHeight) { return true; } mMatrix.postScale(scale, scale, mMiddlePoint.x, mMiddlePoint.y); mLastDistance = getDistance(event); } } break; case MotionEvent.ACTION_UP: CURR_MODE = MODE_NONE; break; case MotionEvent.ACTION_POINTER_UP: CURR_MODE = MODE_POINTER_UP; break; } setImageMatrix(mMatrix); return true; } /** * 两点的距离 */ private float getDistance(MotionEvent event) { float x = event.getX(0) - event.getX(1); float y = event.getY(0) - event.getY(1); return (float) Math.sqrt(x * x + y * y); } /** * 两点的中点 */ private void midPoint(PointF point, MotionEvent event) { float x = event.getX(0) + event.getX(1); float y = event.getY(0) + event.getY(1); point.set(x / 2, y / 2); } /** * 横向、纵向居中 */ protected void center() { float height = mBitmapHeight; float width = mBitmapWidth; float screenWidth = getWidth(); float screenHeight = getHeight(); float scale = 1f; if (width >= height) { scale = screenWidth / width; if (scale * height < mTargetHeight) { scale = mTargetHeight / height; } } else { if (height <= screenHeight) { scale = screenWidth / width; } else { scale = screenHeight / height; } if (scale * width < mTargetWidth) { scale = mTargetWidth / width; } } float deltaX = (screenWidth - width * scale) / 2f; float deltaY = (screenHeight - height * scale) / 2f; mMatrix.postScale(scale, scale); mMatrix.postTranslate(deltaX, deltaY); setImageMatrix(mMatrix); } /** * 获得屏幕宽度 */ public static int getScreenWidth(Context context) { WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics outMetrics = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(outMetrics); return outMetrics.widthPixels; } /** * 获得屏幕高度 */ public static int getScreenHeight(Context context) { WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics outMetrics = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(outMetrics); return outMetrics.heightPixels; } }