Realize Android photo selection area function
Mainly refer to PQPO /SmartCropper
1, according to
Showing four edges and eight dots,
Eight points: The midpoint of four corners and four sides
/* Clipped area, 0, top left -> LeftTop, 1, top right -> RightTop, 2, bottom right -> RightBottom, 3, bottom left -> LeftBottom */ Point; [] mEdgeMidPoints;Copy the code
draw
Protected void onDrawCropPoint(Canvas Canvas) {// Draw a mask onDrawMask(Canvas); // Draw the guideline (canvas); // Draw the selection line onDrawLines(canvas); // Draw anchor point ondrawPoint (canvas); // draw magnifier //... }Copy the code
Specific drawing part:
Draw eight points
protected void onDrawPoints(Canvas canvas) { if (! checkPoints(mCropPoints)) { return; } // Draw 4 corners for (Point Point: mCropPoints) { canvas.drawCircle(getViewPointX(point), getViewPointY(point), dp2px(POINT_RADIUS), mPointFillPaint); canvas.drawCircle(getViewPointX(point), getViewPointY(point), dp2px(POINT_RADIUS), mPointPaint); } if (mShowEdgeMidPoint) { setEdgeMidPoints(); // Draw the midpoints of 4 edges for (Point Point: mEdgeMidPoints){ canvas.drawCircle(getViewPointX(point), getViewPointY(point), dp2px(POINT_RADIUS), mPointFillPaint); canvas.drawCircle(getViewPointX(point), getViewPointY(point), dp2px(POINT_RADIUS), mPointPaint); }}}Copy the code
Before drawing the midpoints of the four edges,
Figure out the midpoints of the current four edges
Public void setEdgeMidPoints(){mEdgeMidPoints == null {mEdgeMidPoints = new points [4]; for (int i = 0; i < mEdgeMidPoints.length; i++){ mEdgeMidPoints[i] = new Point(); Len = McRoppoint.length; len = McRoppoint.length; for (int i = 0; i < len; // To avoid extreme cases, MEdgeMidPoints [I].set(mCropPoints[I].x + (mCropPoints[(I +1)%len].x-mcroppoints [I].x)/2, mCropPoints[i].y + (mCropPoints[(i+1)%len].y - mCropPoints[i].y)/2); }}Copy the code
2, the drag
Drag is divided into two cases, corner drag, midpoint translation
8 types, 4 corner drag, 4 midpoint pan
enum DragPointType{ LEFT_TOP, RIGHT_TOP, RIGHT_BOTTOM, LEFT_BOTTOM, TOP, RIGHT, BOTTOM, LEFT; // Determine the Angle drag, Not middle shift public static Boolean isEdgePoint (DragPointType type) {return type = = TOP | | type = = RIGHT | | type = = BOTTOM | | type == LEFT; }}Copy the code
Mobile processing
@Override public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); boolean handle = true; Switch (action) {case motionEvent. ACTION_DOWN: mDraggingPoint = getNearbyPoint(event); if (mDraggingPoint == null) { handle = false; } break; ACTION_MOVE: // toImagePointSize(mDraggingPoint, event); break; ACTION_UP: // Lift the finger, // cancel mDraggingPoint = null; break; } // draw invalidate(); return handle || super.onTouchEvent(event); }Copy the code
Identify the current point
Parameter Name Parameter Meaning Private Point getNearbyPoint(MotionEvent event) {parameter Name Parameter Meaning if (changing (mCropPoints)) {Point p: checkPoints MCropPoints) {if (isTouchPoint(p, event)) return p; } // checkPoints: checkPoints, checkPoints, and checkPoints MEdgeMidPoints){if (isTouchPoint(p, event)) return p; } } return null; }Copy the code
To find the current point
private static final float TOUCH_POINT_CATCH_DISTANCE = 15; private boolean isTouchPoint(Point p, MotionEvent event){ float x = event.getX(); float y = event.getY(); float px = getViewPointX(p); float py = getViewPointY(p); double distance = Math.sqrt(Math.pow(x - px, 2) + Math.pow(y - py, 2)); If (distance < dp2px(TOUCH_POINT_CATCH_DISTANCE)) {return true; } return false; }Copy the code
2.1. Corner drag
Let’s start with four corner drags
private void toImagePointSize(Point dragPoint, MotionEvent event) { if (dragPoint == null) { return; DragPointType pointType = getPointType(dragPoint); int x = (int) ((Math.min(Math.max(event.getX(), mActLeft), mActLeft + mActWidth) - mActLeft) / mScaleX); int y = (int) ((Math.min(Math.max(event.getY(), mActTop), mActTop + mActHeight) - mActTop) / mScaleY); // Judge can move //... if (DragPointType.isEdgePoint(pointType)){ // ... } else {// dragPoint. Y = y; // dragPoint. dragPoint.x = x; }}Copy the code
Find the current movement type,
Corner drag or midpoint translation
Private DragPointType getPointType(Point dragPoint){if (dragPoint == null) return null; DragPointType type; If (checkPoints(mCropPoints) {int I = 0; i < mCropPoints.length; I ++) {if (dragPoint == mCropPoints[I]) {type = dragpointType.values ()[I]; return type; } // If (initialization (mEdgeMidPoints) {int I = 0; i < mEdgeMidPoints.length; If (dragPoint == mEdgeMidPoints[I]){if (dragPoint == mEdgeMidPoints[I]){if (dragPoint == mEdgeMidPoints[I]){ return type; } } } return null; }Copy the code
2.2. Midpoint translation
private void toImagePointSize(Point dragPoint, MotionEvent event) { if (dragPoint == null) { return; } DragPointType pointType = getPointType(dragPoint); int x = // ... int y = // ... // Judge can move //... If (DragPointType isEdgePoint (pointType)) {/ / middle shift, / / get, an offset vector int xoff = x - dragPoint. X. int yoff = y - dragPoint.y; moveEdge(pointType, xoff, yoff); } else {// corner drag //... }}Copy the code
Take the offset vector and modify the coordinates of the corresponding two vertices
private void moveEdge(DragPointType type, int xoff, int yoff){ switch (type){ case TOP: MovePoint (McRoppoint [P_LT], 0, yoff); movePoint(mCropPoints[P_RT], 0, yoff); break; MCropPoints [P_RT], xoff, 0); movePoint(mCropPoints[P_RB], xoff, 0); break; Case BOTTOM: // down //... Case LEFT: // LEFT //... default: break; }}Copy the code
Simple translation code
Get the offset vector, change the coordinates, and we’re done
private void movePoint(Point point, int xoff, int yoff){ if (point == null) return; int x = point.x + xoff; int y = point.y + yoff; / / check the border if (x < 0 | | x > getDrawable () getIntrinsicWidth ()) return; if (y < 0 || y > getDrawable().getIntrinsicHeight()) return; point.x = x; point.y = y; }Copy the code
Midpoint translation enhancement
The midpoint here is shifted, and when I get my shift vector,
Add directly to the two corner points next to the midpoint
The effect is enhanced to a midpoint translation, where the two corners next to the midpoint are shifted along both sides
- The calculations are a little bit more complicated,
I know where I am before the midpoint, and where I am after the midpoint,
I know the slope of the midpoint and the corner,
We know the slope on the other side of this Angle
I know the Angle, where I was before I shifted it,
So let’s figure out what the Angle is, what the shifted position is
This is an equation solving website
- It might be easier to switch coordinates
Related to making
Gradle configuration for Demo