Android Custom View Implementation of Drag and Scalable Rectangular Box
- 2021-12-04 11:19:02
- OfStack
In this article, we share the specific code of Android custom View drag-and-zoom rectangular box for your reference. The specific contents are as follows
In the development project, a rectangular box is needed to realize the screen capture function, and it is also necessary to drag and zoom at will, which requires custom View. The specific functions are as follows:
1. Customize View
package com.xinrui.screenshot.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
public class CropRectView extends View {
// Draw Damage box and damage name
private Paint mPaint;
private RectF mRectF;
// Edge font
// private BorderedText mBorderedText;
// Title Or Name
private String mTitle;
// Probability
private float mConfidence;
// Rectangular frame corner Angle of: right angle, round corner
private int mCornerAngle;
// Right angle Default
public static final int RIGHT_CORNER = 0;
// Fillet
public static final int ROUND_CORNER = 1;
// Remove Rect
private int MODE;
private static final int MODE_OUTSIDE = 0x000000aa;/*170*/
private static final int MODE_INSIDE = 0x000000bb;/*187*/
private static final int MODE_POINT = 0X000000cc;/*204*/
private static final int MODE_ILLEGAL = 0X000000dd;/*221*/
private float startX;/*start X location*/
private float startY;/*start Y location*/
private float endX;/*end X location*/
private float endY;/*end Y location*/
private float currentX;/*X coordinate values while finger press*/
private float currentY;/*Y coordinate values while finger press*/
private float memoryX;/*the last time the coordinate values of X*/
private float memoryY;/*the last time the coordinate values of Y*/
private float mCoverWidth;/*width of selection box*/
private float mCoverHeight;/*height of selection box*/
private static final int ACCURACY = 100;/*touch accuracy*/
private int pointPosition;/*vertex of a rectangle*/
private static final float minWidth = 100.0f;/*the minimum width of the rectangle*/
private static final float minHeight = 200.0f;/*the minimum height of the rectangle*/
private onLocationListener mLocationListener;/*listen to the Rect */
private static final float EDGE_WIDTH = 1.8f;
public MoveAndCropRectView(Context context) {
this(context, null);
}
public MoveAndCropRectView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public MoveAndCropRectView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initDatas(context);
}
private void initDatas(Context context) {
mPaint = new Paint();
mRectF = new RectF();
// Brush setting hollow
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.WHITE);
mPaint.setStrokeWidth(2);
mPaint.setAntiAlias(true);
// float textSizePx = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
// 18.0f, context.getResources().getDisplayMetrics());
// mBorderedText = new BorderedText(textSizePx);
currentX = 0;
currentY = 0;
}
private boolean firstDraw = true;
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// switch (mCornerAngle) {
// case RIGHT_CORNER:// Draw Damage box ( Right-angled rectangular frame )
// drawRect(canvas);
// break;
// case ROUND_CORNER:// Draw Damage box ( Rounded rectangular frame )
// drawRoundRect(canvas);
// break;
// }
if (firstDraw) {
firstDraw = false;
startX = mRectF.left;
startY = mRectF.top;
endX = mRectF.right;
endY = mRectF.bottom;
mCoverWidth = mRectF.width();
mCoverHeight = mRectF.height();
}
if (mLocationListener != null) {
mLocationListener.locationRect(startX, startY, endX, endY);
}
// LogUtils.d("onDraw -- startX: " + startX);
canvas.drawLine(startX - EDGE_WIDTH, startY - EDGE_WIDTH,
endX + EDGE_WIDTH, startY - EDGE_WIDTH, mPaint);/*top Top border -*/
canvas.drawLine(startX - EDGE_WIDTH, endY + EDGE_WIDTH,
endX + EDGE_WIDTH, endY + EDGE_WIDTH, mPaint);/*bottom -*/
canvas.drawLine(startX - EDGE_WIDTH, startY - EDGE_WIDTH,
startX - EDGE_WIDTH, endY + EDGE_WIDTH, mPaint);/*left |*/
canvas.drawLine(endX + EDGE_WIDTH, startY - EDGE_WIDTH,
endX + EDGE_WIDTH, endY + EDGE_WIDTH, mPaint);/*right |*/
// Drawing name And Probability
// final String labelString =
// !TextUtils.isEmpty(mTitle)
// ? String.format("%s %.2f", mTitle, (100 * mConfidence))
// : String.format("%.2f", (100 * mConfidence));
//
// // In Right-angled rectangular frame Write on
// mBorderedText.drawText(canvas,
// startX,
// startY, labelString + "%",
// mPaint);
}
@SuppressWarnings("NullableProblems")
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
memoryX = event.getX();
memoryY = event.getY();
checkMode(memoryX, memoryY);
break;
case MotionEvent.ACTION_MOVE: {
currentX = event.getX();
currentY = event.getY();
switch (MODE) {
case MODE_ILLEGAL:
recoverFromIllegal(currentX, currentY);
postInvalidate();
break;
case MODE_OUTSIDE:
//do nothing;
break;
case MODE_INSIDE:// Drag
moveByTouch(currentX, currentY);
postInvalidate();
break;
default:
/*MODE_POINT*/
moveByPoint(currentX, currentY);
postInvalidate();
break;
}
}
break;
case MotionEvent.ACTION_UP:
// mPaint.setColor(getContext().getResources().getColor(R.color.orange));
postInvalidate();
break;
default:
break;
}
return true;
}
/* Zoom processing when clicking near vertices */
@SuppressWarnings("SuspiciousNameCombination")
private void moveByPoint(float bx, float by) {
// LogUtils.d("moveByPoint");
switch (pointPosition) {
case 0:/*left-up*/
mCoverWidth = Math.abs(endX - bx);
mCoverHeight = Math.abs(endY - by);
//noinspection SuspiciousNameCombination
if (!checkLegalRect(mCoverWidth, mCoverHeight)) {
MODE = MODE_ILLEGAL;
} else {
refreshLocation(bx, by, endX, endY);
}
break;
case 1:/*right-up*/
mCoverWidth = Math.abs(bx - startX);
mCoverHeight = Math.abs(endY - by);
if (!checkLegalRect(mCoverWidth, mCoverHeight)) {
MODE = MODE_ILLEGAL;
} else {
refreshLocation(startX, by, bx, endY);
}
break;
case 2:/*left-down*/
mCoverWidth = Math.abs(endX - bx);
mCoverHeight = Math.abs(by - startY);
if (!checkLegalRect(mCoverWidth, mCoverHeight)) {
MODE = MODE_ILLEGAL;
} else {
refreshLocation(bx, startY, endX, by);
}
break;
case 3:/*right-down*/
mCoverWidth = Math.abs(bx - startX);
mCoverHeight = Math.abs(by - startY);
if (!checkLegalRect(mCoverWidth, mCoverHeight)) {
MODE = MODE_ILLEGAL;
} else {
refreshLocation(startX, startY, bx, by);
}
break;
default:
break;
}
}
/* Refresh the coordinates of the rectangle */
private void refreshLocation(float isx, float isy, float iex, float iey) {
this.startX = isx;
this.startY = isy;
this.endX = iex;
this.endY = iey;
mCoverWidth = endX - startX;
mCoverHeight = endY - startY;
}
/* Detect whether the rectangle reaches the minimum value */
private boolean checkLegalRect(float cHeight, float cWidth) {
return (cHeight > minHeight && cWidth > minWidth);
}
/* Recovery from illegal state, where the treatment is to stretch and enlarge after reaching the minimum value */
private void recoverFromIllegal(float rx, float ry) {
if ((rx > startX && ry > startY) && (rx < endX && ry < endY)) {
MODE = MODE_ILLEGAL;
} else {
MODE = MODE_POINT;
}
}
/**
* Where is the judgment point in the rectangle
* @param cx
* @param cy
*/
private void checkMode(float cx, float cy) {
if (cx > startX && cx < endX && cy > startY && cy < endY) {
MODE = MODE_INSIDE;// Rectangular interior
} else if (nearbyPoint(cx, cy) < 4) {
MODE = MODE_POINT;// On a rectangular point
} else {
MODE = MODE_OUTSIDE;// Rectangular exterior
}
}
/* The rectangle moves with the finger */
private void moveByTouch(float mx, float my) {/*move center point*/
float dX = mx - memoryX;
float dY = my - memoryY;
startX += dX;
startY += dY;
if(startX<=0){
startX=0;
}
if(startY<=0){
startY=0;
}
endX = startX + mCoverWidth;
endY = startY + mCoverHeight;
if(endX>=1920){
endX=1920;
startX=endX-mCoverWidth;
}
if(endY>=1080){
endY=1080;
startY=endY-mCoverHeight;
}
memoryX = mx;
memoryY = my;
}
/* Judgement point (inX,inY) Is it close to the rectangular 4 Vertex */
private int nearbyPoint(float floatX, float floatY) {
if ((Math.abs(startX - floatX) <= ACCURACY && (Math.abs(floatY - startY) <= ACCURACY))) {/*left-up angle*/
pointPosition = 0;
return 0;
}
if ((Math.abs(endX - floatX) <= ACCURACY && (Math.abs(floatY - startY) <= ACCURACY))) {/*right-up angle*/
pointPosition = 1;
return 1;
}
if ((Math.abs(startX - floatX) <= ACCURACY && (Math.abs(floatY - endY) <= ACCURACY))) {/*left-down angle*/
pointPosition = 2;
return 2;
}
if ((Math.abs(endX - floatX) <= ACCURACY && (Math.abs(floatY - endY) <= ACCURACY))) {/*right-down angle*/
pointPosition = 3;
return 3;
}
pointPosition = 100;
return 100;
}
// Set rectangular box
public void setRectF(RectF rectf) {
this.mRectF = rectf;
}
public void setTitle(String title) {
mTitle = title;
}
public void setConfidence(float confidence) {
mConfidence = confidence;
}
public void setCornerAngle(int cornerAngle) {
this.mCornerAngle = cornerAngle;
}
// Draw Damage box ( Right-angled rectangular frame )
private void drawRect(Canvas canvas) {
canvas.drawRect(mRectF, mPaint);
// Drawing name And Probability
// final String labelString =
// !TextUtils.isEmpty(mTitle)
// ? String.format("%s %.2f", mTitle, (100 * mConfidence))
// : String.format("%.2f", (100 * mConfidence));
// In Right-angled rectangular frame Write on
// mBorderedText.drawText(canvas,
// mRectF.left,
// mRectF.top, labelString + "%",
// mPaint);
}
// Draw Damage box ( Rounded rectangular frame )
private void drawRoundRect(Canvas canvas) {
float cornerSize = Math.min(mRectF.width(), mRectF.height()) / 8.0f;
canvas.drawRoundRect(mRectF, cornerSize, cornerSize, mPaint);
// Drawing name And Probability
// final String labelString =
// !TextUtils.isEmpty(mTitle)
// ? String.format("%s %.2f", mTitle, (100 * mConfidence))
// : String.format("%.2f", (100 * mConfidence));
// In Rounded rectangular frame Write on
// mBorderedText.drawText(canvas,
// mRectF.left + cornerSize,
// mRectF.top, labelString + "%",
// mPaint);
}
public void setLocationListener(onLocationListener mLocationListener) {
this.mLocationListener = mLocationListener;
}
public interface onLocationListener {
void locationRect(float startX, float startY, float endX, float endY);
}
}
2. Application in Activity
package com.xinrui.screenshot;
import android.app.Activity;
import android.graphics.RectF;
import android.os.Bundle;
import android.util.Log;
import android.widget.RelativeLayout;
import com.xinrui.screenshot.view.CropRectView;
public class MainActivity extends Activity {
private RelativeLayout main_area;
CropRectView cropRectView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initview();
}
private void initview(){
main_area = (RelativeLayout)findViewById(R.id.main_area);
cropRectView = (CropRectView)findViewById(R.id.main_img);
RectF rectF = new RectF(660, 240, 1260, 840);
cropRectView.setRectF(rectF);
cropRectView.setLocationListener(new CropRectView.onLocationListener() {
@Override
public void locationRect(float startX, float startY, float endX, float endY) {
Log.e("MainActivity","[ startX:(" + startX + ")--startY:(" + startY + ")--endX:(" + endX + ")--endY:(" + endY + ") ]");
}
});
}
}
3.activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_area"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.xinrui.screenshot.view.CropRectView
android:id="@+id/main_img"
android:layout_centerInParent="true"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
You're done.