效果图:
public class CropImageView extends AppCompatImageView {
private ContextmContext;
//裁剪框边框画笔
private PaintmBorderPaint;
//裁剪框九宫格画笔
private PaintmGuidelinePaint;
//绘制裁剪边框四个角的画笔
private PaintmCornerPaint;
//判断手指位置是否处于缩放裁剪框位置的范围:如果是当手指移动的时候裁剪框会相应的变化大小
//否则手指移动的时候就是拖动裁剪框使之随着手指移动
private float mScaleRadius;
private float mCornerThickness;
private float mBorderThickness;
//四个角小短边的长度
private float mCornerLength;
//用来表示图片边界的矩形
private RectFmBitmapRect =new RectF();
//手指位置距离裁剪框的偏移量
private PointFmTouchOffset =new PointF();
private CropWindowEdgeSelectormPressedCropWindowEdgeSelector;
private float oldW =0f;
private float oldH =0f;
private RectFodlBitmapRect =new RectF();
public CropImageView(Context context) {
super(context);
init(context);
}
public CropImageView(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
init(context);
}
/**
* 里面的值暂时写死,也可以从AttributeSet里面来配置
*
* @param context
*/
private void init(@NonNull Context context) {
mContext = context;
mBorderPaint =new Paint(Paint.ANTI_ALIAS_FLAG);
mBorderPaint.setStrokeWidth(UIUtil.dip2px(context, 3));
mBorderPaint.setColor(Color.parseColor("#AA000000"));
mGuidelinePaint =new Paint(Paint.ANTI_ALIAS_FLAG);
mGuidelinePaint.setStyle(Paint.Style.STROKE);
mGuidelinePaint.setStrokeWidth(UIUtil.dip2px(context, 1));
mGuidelinePaint.setColor(Color.parseColor("#AAFFFFFF"));
mCornerPaint =new Paint(Paint.ANTI_ALIAS_FLAG);
mCornerPaint.setStyle(Paint.Style.STROKE);
mCornerPaint.setStrokeWidth(UIUtil.dip2px(context, 5));
mCornerPaint.setColor(Color.WHITE);
mScaleRadius = UIUtil.dip2px(context, 24);
mBorderThickness = UIUtil.dip2px(context, 3);
mCornerThickness = UIUtil.dip2px(context, 5);
mCornerLength = UIUtil.dip2px(context, 20);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mBitmapRect = getBitmapRect();
initCropWindow(mBitmapRect);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制九宫格引导线
// drawGuidelines(canvas);
//绘制裁剪边框
drawBorder(canvas);
//绘制裁剪边框的四个角
drawCorners(canvas);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()) {
return false;
}
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
onActionDown(event.getX(), event.getY());
return true;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
getParent().requestDisallowInterceptTouchEvent(false);
onActionUp();
return true;
case MotionEvent.ACTION_MOVE:
onActionMove(event.getX(), event.getY());
getParent().requestDisallowInterceptTouchEvent(true);
return true;
default:
return false;
}
}
/**
* 获取裁剪好的BitMap
*/
public BitmapgetCroppedImage() {
final Drawable drawable = getDrawable();
if (!(drawableinstanceof BitmapDrawable)) {
return null;
}
final Bitmap originalBitmap = ((BitmapDrawable) drawable).getBitmap();
double aY = originalBitmap.getHeight() / (float) (mBitmapRect.bottom -mBitmapRect.top);
double aX = originalBitmap.getWidth() / (float) (mBitmapRect.right -mBitmapRect.left);
float cropX = (float) (aX * (Edge.LEFT.getCoordinate() -mBitmapRect.left));
float cropY = (float) (aY * (Edge.TOP.getCoordinate() -mBitmapRect.top));
final float cropWidth = (float) (aX * Edge.getWidth());
final float cropHeight = (float) (aY * Edge.getHeight());
return Bitmap.createBitmap(originalBitmap,
(int) cropX,
(int) cropY,
(int) cropWidth,
(int) cropHeight
);
}
/**
* 获取图片ImageView周围的边界组成的RectF对象
*/
private RectFgetBitmapRect() {
final Drawable drawable = getDrawable();
if (drawable ==null) {
return new RectF();
}
final float[] matrixValues =new float[9];
getImageMatrix().getValues(matrixValues);
final float scaleX = matrixValues[Matrix.MSCALE_X];
final float scaleY = matrixValues[Matrix.MSCALE_Y];
final float transX = matrixValues[Matrix.MTRANS_X];
final float transY = matrixValues[Matrix.MTRANS_Y];
final int drawableIntrinsicWidth = drawable.getIntrinsicWidth();
final int drawableIntrinsicHeight = drawable.getIntrinsicHeight();
final int drawableDisplayWidth = Math.round(drawableIntrinsicWidth * scaleX);
final int drawableDisplayHeight = Math.round(drawableIntrinsicHeight * scaleY);
final float left = Math.max(transX, 0);
final float top = Math.max(transY, 0);
final float right = Math.min(left + drawableDisplayWidth, getWidth());
final float bottom = Math.min(top + drawableDisplayHeight, getHeight());
return new RectF(left, top, right, bottom);
}
/**
* 初始化裁剪框
*
* @param bitmapRect
*/
private boolean isOne =true;
private void initCropWindow(@NonNull RectF bitmapRect) {
if (isOne) {
odlBitmapRect = bitmapRect;
oldW = bitmapRect.right - bitmapRect.left;
oldH = bitmapRect.bottom - bitmapRect.top;
isOne =false;
//裁剪框距离图片左右的padding值
final float horizontalPadding =0.2f * bitmapRect.width();
final float verticalPadding =0.2f * bitmapRect.height();
// if (getHeight() > getWidth()) {
// Edge.LEFT.initCoordinate(bitmapRect.left - ((bitmapRect.left - bitmapRect.right) / 4f));
// Edge.TOP.initCoordinate(((bitmapRect.top + bitmapRect.bottom) / 2f) - ((bitmapRect.left - bitmapRect.right) / 8f));
// Edge.RIGHT.initCoordinate(bitmapRect.right + ((bitmapRect.left - bitmapRect.right) / 4f));
// Edge.BOTTOM.initCoordinate(((bitmapRect.top + bitmapRect.bottom) / 2f )+ ((bitmapRect.left - bitmapRect.right) / 8f));
// }else {
//
// }
//初始化裁剪框上下左右四条边
Edge.LEFT.initCoordinate(bitmapRect.left + horizontalPadding);
Edge.TOP.initCoordinate(bitmapRect.top + verticalPadding);
Edge.RIGHT.initCoordinate(bitmapRect.right - horizontalPadding);
Edge.BOTTOM.initCoordinate(bitmapRect.bottom - verticalPadding);
}else {
//变形后的宽高0>90 90->180 180->270 270->360
float newW = bitmapRect.right - bitmapRect.left;
float newH = bitmapRect.bottom - bitmapRect.top;
float newWB = newH /oldW;
float newWH = newW /oldH;
float newT = bitmapRect.top + (newWB * (Edge.LEFT.getCoordinate() -odlBitmapRect.left));
float newR = bitmapRect.right - (newWH * (Edge.TOP.getCoordinate() -odlBitmapRect.top));
float newB = bitmapRect.bottom - (newWB * (odlBitmapRect.right - Edge.RIGHT.getCoordinate()));
float newL = bitmapRect.left + (newWH * (odlBitmapRect.bottom - Edge.BOTTOM.getCoordinate()));
Edge.TOP.initCoordinate(newT);
Edge.RIGHT.initCoordinate(newR);
Edge.BOTTOM.initCoordinate(newB);
Edge.LEFT.initCoordinate(newL);
odlBitmapRect = bitmapRect;
oldW = bitmapRect.right - bitmapRect.left;
oldH = bitmapRect.bottom - bitmapRect.top;
}
}
private void drawGuidelines(@NonNull Canvas canvas) {
final float left = Edge.LEFT.getCoordinate();
final float top = Edge.TOP.getCoordinate();
final float right = Edge.RIGHT.getCoordinate();
final float bottom = Edge.BOTTOM.getCoordinate();
final float oneThirdCropWidth = Edge.getWidth() /3;
final float x1 = left + oneThirdCropWidth;
//引导线竖直方向第一条线
canvas.drawLine(x1, top, x1, bottom, mGuidelinePaint);
final float x2 = right - oneThirdCropWidth;
//引导线竖直方向第二条线
canvas.drawLine(x2, top, x2, bottom, mGuidelinePaint);
final float oneThirdCropHeight = Edge.getHeight() /3;
final float y1 = top + oneThirdCropHeight;
//引导线水平方向第一条线
canvas.drawLine(left, y1, right, y1, mGuidelinePaint);
final float y2 = bottom - oneThirdCropHeight;
//引导线水平方向第二条线
canvas.drawLine(left, y2, right, y2, mGuidelinePaint);
}
//画4边蒙版
private void drawBorder(@NonNull Canvas canvas) {
//上蒙版
canvas.drawRect(0f, 0f, getWidth(), Edge.TOP.getCoordinate(), mBorderPaint);
//左蒙版
canvas.drawRect(0f, Edge.TOP.getCoordinate() -0.22f, Edge.LEFT.getCoordinate(), Edge.BOTTOM.getCoordinate() +0.22f, mBorderPaint);
//下蒙版
canvas.drawRect(0f, Edge.BOTTOM.getCoordinate(), getWidth(), getHeight(), mBorderPaint);
//右蒙版
canvas.drawRect(Edge.RIGHT.getCoordinate(), Edge.TOP.getCoordinate() -0.22f, getWidth(), Edge.BOTTOM.getCoordinate() +0.22f, mBorderPaint);
}
private void drawCorners(@NonNull Canvas canvas) {
final float left = Edge.LEFT.getCoordinate();
final float top = Edge.TOP.getCoordinate();
final float right = Edge.RIGHT.getCoordinate();
final float bottom = Edge.BOTTOM.getCoordinate();
//简单的数学计算
final float lateralOffset = (mCornerThickness -mBorderThickness) /2f;
final float startOffset =mCornerThickness - (mBorderThickness /2f);
mCornerPaint.setStrokeCap(Paint.Cap.ROUND);
mCornerPaint.setStrokeJoin(Paint.Join.ROUND);
//左上角
Path path1 =new Path();
path1.moveTo(left - lateralOffset, top +mCornerLength);
path1.lineTo(left - lateralOffset, top - lateralOffset);
path1.lineTo(left +mCornerLength, top - lateralOffset);
canvas.drawPath(path1, mCornerPaint);
//右上角
Path path2 =new Path();
path2.moveTo(right -mCornerLength, top - lateralOffset);
path2.lineTo(right + lateralOffset, top - lateralOffset);
path2.lineTo(right + lateralOffset, top +mCornerLength);
canvas.drawPath(path2, mCornerPaint);
// //右上角右面的短线
// canvas.drawLine(right + lateralOffset, top - startOffset, right + lateralOffset, top + mCornerLength, mCornerPaint);
// //右上角上面的短线
// canvas.drawLine(right + startOffset, top - lateralOffset, right - mCornerLength, top - lateralOffset, mCornerPaint);
//左下角
Path path3 =new Path();
path3.moveTo(left - lateralOffset, bottom -mCornerLength);
path3.lineTo(left - lateralOffset, bottom + lateralOffset);
path3.lineTo(left +mCornerLength, bottom + lateralOffset);
canvas.drawPath(path3, mCornerPaint);
// canvas.drawLine(left - lateralOffset, bottom + startOffset, left - lateralOffset, bottom - mCornerLength, mCornerPaint);
// //左下角底部的短线
// canvas.drawLine(left - startOffset, bottom + lateralOffset, left + mCornerLength, bottom + lateralOffset, mCornerPaint);
//右下角左面的短线
Path path4 =new Path();
path4.moveTo(right + lateralOffset, bottom -mCornerLength);
path4.lineTo(right + lateralOffset, bottom + lateralOffset);
path4.lineTo(right -mCornerLength, bottom + lateralOffset);
canvas.drawPath(path4, mCornerPaint);
// canvas.drawLine(right + lateralOffset, bottom + startOffset, right + lateralOffset, bottom - mCornerLength, mCornerPaint);
// //右下角底部的短线
// canvas.drawLine(right + startOffset, bottom + lateralOffset, right - mCornerLength, bottom + lateralOffset, mCornerPaint);
}
/**
* 处理手指按下事件
*
* @param x 手指按下时水平方向的坐标
* @param y 手指按下时竖直方向的坐标
*/
private void onActionDown(float x, float y) {
//获取边框的上下左右四个坐标点的坐标
final float left = Edge.LEFT.getCoordinate();
final float top = Edge.TOP.getCoordinate();
final float right = Edge.RIGHT.getCoordinate();
final float bottom = Edge.BOTTOM.getCoordinate();
//获取手指所在位置位于图二种的A,B,C,D位置种哪一种
mPressedCropWindowEdgeSelector = CatchEdgeUtil.getPressedHandle(x, y, left, top, right, bottom, mScaleRadius);
if (mPressedCropWindowEdgeSelector !=null) {
//计算手指按下的位置与裁剪框的偏移量
CatchEdgeUtil.getOffset(mPressedCropWindowEdgeSelector, x, y, left, top, right, bottom, mTouchOffset);
invalidate();
}
}
private void onActionUp() {
if (mPressedCropWindowEdgeSelector !=null) {
mPressedCropWindowEdgeSelector =null;
invalidate();
}
}
private void onActionMove(float x, float y) {
if (mPressedCropWindowEdgeSelector ==null) {
return;
}
x +=mTouchOffset.x;
y +=mTouchOffset.y;
mPressedCropWindowEdgeSelector.updateCropWindow(x, y, mBitmapRect);
invalidate();
}
}
辅助工具类:
/***
* 捕获手指在裁剪框的哪一条边
*/
public class CatchEdgeUtil {
/**
* 判断手指是否的位置是否在有效的缩放区域:缩放区域的半径为targetRadius
* 缩放区域使指:裁剪框的四个角度或者四条边,当手指位置处在某个角
* 或者某条边的时候,则随着手指的移动对裁剪框进行缩放操作。
* 如果手指位于裁剪框的内部,则裁剪框随着手指的移动而只进行移动操作。
* 否则可以判定手指距离裁剪框较远而什么都不做
*/
public static CropWindowEdgeSelector getPressedHandle(float x,
float y,
float left,
float top,
float right,
float bottom,
float targetRadius) {
CropWindowEdgeSelector nearestCropWindowEdgeSelector = null;
//判断手指距离裁剪框哪一个角最近
//最近距离默认正无穷大
float nearestDistance = Float.POSITIVE_INFINITY;
//////////判断手指是否在图二种的A位置:四个角之一/////////////////
//计算手指距离左上角的距离
final float distanceToTopLeft = calculateDistance(x, y, left, top);
if (distanceToTopLeft < nearestDistance) {
nearestDistance = distanceToTopLeft;
nearestCropWindowEdgeSelector = CropWindowEdgeSelector.TOP_LEFT;
}
//计算手指距离右上角的距离
final float distanceToTopRight = calculateDistance(x, y, right, top);
if (distanceToTopRight < nearestDistance) {
nearestDistance = distanceToTopRight;
nearestCropWindowEdgeSelector = CropWindowEdgeSelector.TOP_RIGHT;
}
//计算手指距离左下角的距离
final float distanceToBottomLeft = calculateDistance(x, y, left, bottom);
if (distanceToBottomLeft < nearestDistance) {
nearestDistance = distanceToBottomLeft;
nearestCropWindowEdgeSelector = CropWindowEdgeSelector.BOTTOM_LEFT;
}
//计算手指距离右下角的距离
final float distanceToBottomRight = calculateDistance(x, y, right, bottom);
if (distanceToBottomRight < nearestDistance) {
nearestDistance = distanceToBottomRight;
nearestCropWindowEdgeSelector = CropWindowEdgeSelector.BOTTOM_RIGHT;
}
//如果手指选中了一个最近的角,并且在缩放范围内则返回这个角
if (nearestDistance <= targetRadius) {
return nearestCropWindowEdgeSelector;
}
//////////判断手指是否在图二种的C位置:四个边的某条边/////////////////
if (CatchEdgeUtil.isInHorizontalTargetZone(x, y, left, right, top, targetRadius)) {
return CropWindowEdgeSelector.TOP;//说明手指在裁剪框top区域
} else if (CatchEdgeUtil.isInHorizontalTargetZone(x, y, left, right, bottom, targetRadius)) {
return CropWindowEdgeSelector.BOTTOM;//说明手指在裁剪框bottom区域
} else if (CatchEdgeUtil.isInVerticalTargetZone(x, y, left, top, bottom, targetRadius)) {
return CropWindowEdgeSelector.LEFT;//说明手指在裁剪框left区域
} else if (CatchEdgeUtil.isInVerticalTargetZone(x, y, right, top, bottom, targetRadius)) {
return CropWindowEdgeSelector.RIGHT;//说明手指在裁剪框right区域
}
//////////判断手指是否在图二种的B位置:裁剪框的中间/////////////////
if (isWithinBounds(x, y, left, top, right, bottom)) {
return CropWindowEdgeSelector.CENTER;
}
////////手指位于裁剪框的D位置,此时移动手指什么都不做/////////////
return null;
}
public static void getOffset(@NonNull CropWindowEdgeSelector cropWindowEdgeSelector,
float x,
float y,
float left,
float top,
float right,
float bottom,
@NonNull PointF touchOffsetOutput) {
float touchOffsetX = 0;
float touchOffsetY = 0;
switch (cropWindowEdgeSelector) {
case TOP_LEFT:
touchOffsetX = left - x;
touchOffsetY = top - y;
break;
case TOP_RIGHT:
touchOffsetX = right - x;
touchOffsetY = top - y;
break;
case BOTTOM_LEFT:
touchOffsetX = left - x;
touchOffsetY = bottom - y;
break;
case BOTTOM_RIGHT:
touchOffsetX = right - x;
touchOffsetY = bottom - y;
break;
case LEFT:
touchOffsetX = left - x;
touchOffsetY = 0;
break;
case TOP:
touchOffsetX = 0;
touchOffsetY = top - y;
break;
case RIGHT:
touchOffsetX = right - x;
touchOffsetY = 0;
break;
case BOTTOM:
touchOffsetX = 0;
touchOffsetY = bottom - y;
break;
case CENTER:
final float centerX = (right + left) / 2;
final float centerY = (top + bottom) / 2;
touchOffsetX = centerX - x;
touchOffsetY = centerY - y;
break;
}
touchOffsetOutput.x = touchOffsetX;
touchOffsetOutput.y = touchOffsetY;
}
private static boolean isInHorizontalTargetZone(float x,
float y,
float handleXStart,
float handleXEnd,
float handleY,
float targetRadius) {
return (x > handleXStart && x < handleXEnd && Math.abs(y - handleY) <= targetRadius);
}
private static boolean isInVerticalTargetZone(float x,
float y,
float handleX,
float handleYStart,
float handleYEnd,
float targetRadius) {
return (Math.abs(x - handleX) <= targetRadius && y > handleYStart && y < handleYEnd);
}
private static boolean isWithinBounds(float x, float y, float left, float top, float right, float bottom) {
return x >= left && x <= right && y >= top && y <= bottom;
}
/**
* 计算 (x1, y1) 和 (x2, y2)两个点的距离
*/
private static float calculateDistance(float x1, float y1, float x2, float y2) {
final float side1 = x2 - x1;
final float side2 = y2 - y1;
return (float) Math.sqrt(side1 * side1 + side2 * side2);
}
}
/**
* 表示手指选中的裁剪框的哪一个边:有如下几种情况:
* 手指选中一条边的情况:LEFT,TOP,RIGHT,BOTTOM
* 手指选中两条边的情况:此时手指位于裁剪框的四个角度的某一个:LEFT and TOP, TOP and RIGHT, RIGHT and BOTTOM, BOTTOM and RIGHT
* 手指在裁剪框的中间区域,此时移动手指进行的是平移操作
*/
public enum CropWindowEdgeSelector {
/////////////////////图A///////////////////////////
//左上角:此时是控制裁剪框最上边和最左边的两条边
TOP_LEFT(new CropWindowScaleHelper(Edge.TOP, Edge.LEFT)),
//右上角:此时是控制裁剪框最上边和最右边的两条边
TOP_RIGHT(new CropWindowScaleHelper(Edge.TOP, Edge.RIGHT)),
//左下角:此时是控制裁剪框最下边和最左边的两条边
BOTTOM_LEFT(new CropWindowScaleHelper(Edge.BOTTOM, Edge.LEFT)),
//右下角:此时是控制裁剪框最下边和最右边的两条边
BOTTOM_RIGHT(new CropWindowScaleHelper(Edge.BOTTOM, Edge.RIGHT)),
//////////////////图C/////////////
//仅控制裁剪框左边线
LEFT(new CropWindowScaleHelper(null, Edge.LEFT)),
//仅控制裁剪框右边线
TOP(new CropWindowScaleHelper(Edge.TOP, null)),
//仅控制裁剪框上边线
RIGHT(new CropWindowScaleHelper(null, Edge.RIGHT)),
//仅控制裁剪框下边线
BOTTOM(new CropWindowScaleHelper(Edge.BOTTOM, null)),
//////////////图B//////////////
//中间位置
CENTER(new CropWindowMoveHelper());
private CropWindowScaleHelper mHelper;
CropWindowEdgeSelector(CropWindowScaleHelper helper) {
mHelper = helper;
}
public void updateCropWindow(float x, float y, @NonNull RectF imageRect) {
mHelper.updateCropWindow(x, y, imageRect);
}
}
/**
* 表示手指再裁剪框里面,此时手指移动表明是移动(平移)裁剪框的操作
*/
class CropWindowMoveHelper extends CropWindowScaleHelper {
CropWindowMoveHelper() {
super(null, null);
}
@Override
void updateCropWindow(float x,
float y,
@NonNull RectF imageRect) {
//获取裁剪框的四个坐标位置
float left = Edge.LEFT.getCoordinate();
float top = Edge.TOP.getCoordinate();
float right = Edge.RIGHT.getCoordinate();
float bottom = Edge.BOTTOM.getCoordinate();
//获取裁剪框的中心位置
final float currentCenterX = (left + right) / 2;
final float currentCenterY = (top + bottom) / 2;
//判断手指移动的距离
final float offsetX = x - currentCenterX;
final float offsetY = y - currentCenterY;
//更新裁剪框四条边的坐标
Edge.LEFT.offset(offsetX);
Edge.TOP.offset(offsetY);
Edge.RIGHT.offset(offsetX);
Edge.BOTTOM.offset(offsetY);
//////////////裁剪框越界处理/////////////////
if (Edge.LEFT.isOutsideMargin(imageRect)) {
//获取此时x越界时的坐标位置
float currentCoordinate = Edge.LEFT.getCoordinate();
//重新指定左边的值为初始值
Edge.LEFT.initCoordinate(imageRect.left);
//越界的距离
float offset = Edge.LEFT.getCoordinate() - currentCoordinate;
//修正最右边的偏移量
Edge.RIGHT.offset(offset);
} else if (Edge.RIGHT.isOutsideMargin(imageRect)) {
float currentCoordinate = Edge.RIGHT.getCoordinate();
Edge.RIGHT.initCoordinate(imageRect.right);
float offset = Edge.RIGHT.getCoordinate() - currentCoordinate;
Edge.LEFT.offset(offset);
}
if (Edge.TOP.isOutsideMargin(imageRect)) {
float currentCoordinate = Edge.TOP.getCoordinate();
Edge.TOP.initCoordinate(imageRect.top);
float offset = Edge.TOP.getCoordinate() - currentCoordinate;
Edge.BOTTOM.offset(offset);
} else if (Edge.BOTTOM.isOutsideMargin(imageRect)) {
float currentCoordinate = Edge.BOTTOM.getCoordinate();
Edge.BOTTOM.initCoordinate(imageRect.bottom);
float offset = Edge.BOTTOM.getCoordinate() - currentCoordinate;
Edge.TOP.offset(offset);
}
}
}
/**
* 操控裁剪框的辅助类:操控裁剪框的缩放
*/
class CropWindowScaleHelper {
private Edge mHorizontalEdge;
private Edge mVerticalEdge;
CropWindowScaleHelper(Edge horizontalEdge, Edge verticalEdge) {
mHorizontalEdge = horizontalEdge;
mVerticalEdge = verticalEdge;
}
/**
* 随着手指的移动而改变裁剪框的大小
*
* @param x 手指x方向的位置
* @param y 手指y方向的位置
* @param imageRect 用来表示图片边界的矩形
*/
void updateCropWindow(float x,
float y,
@NonNull RectF imageRect) {
if (mHorizontalEdge != null)
mHorizontalEdge.updateCoordinate(x, y, imageRect);
if (mVerticalEdge != null)
mVerticalEdge.updateCoordinate(x, y, imageRect);
}
}
/**
* 裁剪框上下左右的四个坐标位置:(LEFT,TOP),(LEFT,RIGHT),(RIGHT,BOTTOM),(LEFT,BOTTOM)四个坐标点
* 组成的矩形就是裁剪框
*/
public enum Edge {
LEFT,
TOP,
RIGHT,
BOTTOM;
//裁剪框的最小宽度或者高度
static final int MIN_CROP_LENGTH_PX = 80;
//上下左右边界的的值
private float mCoordinate;
public void initCoordinate(float coordinate) {
mCoordinate = coordinate;
}
/**
* 随着手指的移动而改变坐标值
*
* @param distance
*/
public void offset(float distance) {
mCoordinate += distance;
}
public float getCoordinate() {
return mCoordinate;
}
/**
* 更新某条边的坐标位置
*/
public void updateCoordinate(float x, float y, @NonNull RectF imageRect) {
switch (this) {
case LEFT:
mCoordinate = adjustLeft(x, imageRect);
break;
case TOP:
mCoordinate = adjustTop(y, imageRect);
break;
case RIGHT:
mCoordinate = adjustRight(x, imageRect);
break;
case BOTTOM:
mCoordinate = adjustBottom(y, imageRect);
break;
}
}
/**
* 获取剪切框的宽
*/
public static float getWidth() {
return Edge.RIGHT.getCoordinate() - Edge.LEFT.getCoordinate();
}
/**
* 获取剪切框的高
*/
public static float getHeight() {
return Edge.BOTTOM.getCoordinate() - Edge.TOP.getCoordinate();
}
/**
* 判断裁剪框是否超越图片指定的边界
*/
public boolean isOutsideMargin(@NonNull RectF rect) {
final boolean result;
switch (this) {
case LEFT:
result = mCoordinate - rect.left < 0;
break;
case TOP:
result = mCoordinate - rect.top < 0;
break;
case RIGHT:
result = rect.right - mCoordinate < 0;
break;
default: // BOTTOM
result = rect.bottom - mCoordinate < 0;
break;
}
return result;
}
private static float adjustLeft(float x, @NonNull RectF imageRect) {
final float resultX;
if (x - imageRect.left < 0) {//左边越界
resultX = imageRect.left;
} else {
//防止裁剪框左边超过右边或者最小范围
if ((x + MIN_CROP_LENGTH_PX) >= Edge.RIGHT.getCoordinate()) {
x = Edge.RIGHT.getCoordinate() - MIN_CROP_LENGTH_PX;
}
resultX = x;
}
return resultX;
}
private static float adjustRight(float x, @NonNull RectF imageRect) {
final float resultX;
if (imageRect.right - x < 0) {
resultX = imageRect.right;
} else {
//防止裁剪框右边超过最小范围
if ((x - MIN_CROP_LENGTH_PX) <= Edge.LEFT.getCoordinate()) {
x = Edge.LEFT.getCoordinate() + MIN_CROP_LENGTH_PX;
}
resultX = x;
}
return resultX;
}
private static float adjustTop(float y, @NonNull RectF imageRect) {
final float resultY;
if (y - imageRect.top < 0) {
resultY = imageRect.top;
} else {
//防止裁剪框上边超过最小范围或者越过最下边
if ((y + MIN_CROP_LENGTH_PX) >= Edge.BOTTOM.getCoordinate()) {
y = Edge.BOTTOM.getCoordinate() - MIN_CROP_LENGTH_PX;
}
resultY = y;
}
return resultY;
}
private static float adjustBottom(float y, @NonNull RectF imageRect) {
final float resultY;
if (imageRect.bottom - y < 0) {
resultY = imageRect.bottom;
} else {
if ((y - MIN_CROP_LENGTH_PX) <= Edge.TOP.getCoordinate()) {
y = Edge.TOP.getCoordinate() + MIN_CROP_LENGTH_PX;
}
resultY = y;
}
return resultY;
}
}