Android自定义View实现可拖拽缩放的矩形框

时间:2021-05-20

本文实例为大家分享了Android自定义View拖拽缩放矩形框的具体代码,供大家参考,具体内容如下

在开发项目中,需要一个矩形框来实现截屏功能,并且还需要可以任意拖拽和缩放,这就需要自定义View来实现了,具体功能如下:

1.自定义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 { // 绘制 损害框和损害名称 private Paint mPaint; private RectF mRectF; // 边缘字体// private BorderedText mBorderedText; // 标题 或 名字 private String mTitle; // 概率 private float mConfidence; // 矩形框 corner 的角度:直角、圆角 private int mCornerAngle; //直角 默认 public static final int RIGHT_CORNER = 0; //圆角 public static final int ROUND_CORNER = 1; // Remove Rect private int MODE; private static final int MODE_OUTSIDE = 0x000000aa; private static final int MODE_INSIDE = 0x000000bb; private static final int MODE_POINT = 0X000000cc; private static final int MODE_ILLEGAL = 0X000000dd; private float startX; private float startY; private float endX; private float endY; private float currentX; private float currentY; private float memoryX; private float memoryY; private float mCoverWidth; private float mCoverHeight; private static final int ACCURACY = 100; private int pointPosition; private static final float minWidth = 100.0f; private static final float minHeight = 200.0f; private onLocationListener mLocationListener; 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(); //画笔设置空心 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:// 绘制 损害框(直角矩形框)// drawRect(canvas);// break;// case ROUND_CORNER:// 绘制 损害框(圆角矩形框)// 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); canvas.drawLine(startX - EDGE_WIDTH, endY + EDGE_WIDTH, endX + EDGE_WIDTH, endY + EDGE_WIDTH, mPaint); canvas.drawLine(startX - EDGE_WIDTH, startY - EDGE_WIDTH, startX - EDGE_WIDTH, endY + EDGE_WIDTH, mPaint); canvas.drawLine(endX + EDGE_WIDTH, startY - EDGE_WIDTH, endX + EDGE_WIDTH, endY + EDGE_WIDTH, mPaint); // 绘制名称 和 概率// final String labelString =// !TextUtils.isEmpty(mTitle)// ? String.format("%s %.2f", mTitle, (100 * mConfidence))// : String.format("%.2f", (100 * mConfidence));//// // 在 直角矩形框 上写字// 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://拖动 moveByTouch(currentX, currentY); postInvalidate(); break; default: moveByPoint(currentX, currentY); postInvalidate(); break; } } break; case MotionEvent.ACTION_UP:// mPaint.setColor(getContext().getResources().getColor(R.color.orange)); postInvalidate(); break; default: break; } return true; } @SuppressWarnings("SuspiciousNameCombination") private void moveByPoint(float bx, float by) {// LogUtils.d("moveByPoint"); switch (pointPosition) { case 0: 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: 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: 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: 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; } } 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; } private boolean checkLegalRect(float cHeight, float cWidth) { return (cHeight > minHeight && cWidth > minWidth); } private void recoverFromIllegal(float rx, float ry) { if ((rx > startX && ry > startY) && (rx < endX && ry < endY)) { MODE = MODE_ILLEGAL; } else { MODE = MODE_POINT; } } /** * 判断点在矩形的什么位置 * @param cx * @param cy */ private void checkMode(float cx, float cy) { if (cx > startX && cx < endX && cy > startY && cy < endY) { MODE = MODE_INSIDE;//矩形内部 } else if (nearbyPoint(cx, cy) < 4) { MODE = MODE_POINT;//矩形点上 } else { MODE = MODE_OUTSIDE;//矩形外部 } } private void moveByTouch(float mx, float my) { 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; } private int nearbyPoint(float floatX, float floatY) { if ((Math.abs(startX - floatX) <= ACCURACY && (Math.abs(floatY - startY) <= ACCURACY))) { pointPosition = 0; return 0; } if ((Math.abs(endX - floatX) <= ACCURACY && (Math.abs(floatY - startY) <= ACCURACY))) { pointPosition = 1; return 1; } if ((Math.abs(startX - floatX) <= ACCURACY && (Math.abs(floatY - endY) <= ACCURACY))) { pointPosition = 2; return 2; } if ((Math.abs(endX - floatX) <= ACCURACY && (Math.abs(floatY - endY) <= ACCURACY))) { pointPosition = 3; return 3; } pointPosition = 100; return 100; } // 设置矩形框 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; } // 绘制 损害框(直角矩形框) private void drawRect(Canvas canvas) { canvas.drawRect(mRectF, mPaint); // 绘制名称 和 概率// final String labelString =// !TextUtils.isEmpty(mTitle)// ? String.format("%s %.2f", mTitle, (100 * mConfidence))// : String.format("%.2f", (100 * mConfidence)); // 在 直角矩形框 上写字// mBorderedText.drawText(canvas,// mRectF.left,// mRectF.top, labelString + "%",// mPaint); } // 绘制 损害框(圆角矩形框) private void drawRoundRect(Canvas canvas) { float cornerSize = Math.min(mRectF.width(), mRectF.height()) / 8.0f; canvas.drawRoundRect(mRectF, cornerSize, cornerSize, mPaint); // 绘制名称 和 概率// final String labelString =// !TextUtils.isEmpty(mTitle)// ? String.format("%s %.2f", mTitle, (100 * mConfidence))// : String.format("%.2f", (100 * mConfidence)); // 在 圆角矩形框 上写字// 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.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>

大功告成。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。

相关文章