Android自定义View实现可拖拽缩放的矩形框
本文实例为大家分享了Android自定义View拖拽缩放矩形框的具体代码,供大家参考,具体内容如下
在开发项目中,需要一个矩形框来实现截屏功能,并且还需要可以任意拖拽和缩放,这就需要自定义View来实现了,具体功能如下:
1.自定义View
packagecom.xinrui.screenshot.view;
importandroid.content.Context;
importandroid.graphics.Canvas;
importandroid.graphics.Color;
importandroid.graphics.Paint;
importandroid.graphics.RectF;
importandroid.support.annotation.Nullable;
importandroid.util.AttributeSet;
importandroid.util.Log;
importandroid.util.TypedValue;
importandroid.view.MotionEvent;
importandroid.view.View;
publicclassCropRectViewextendsView{
//绘制损害框和损害名称
privatePaintmPaint;
privateRectFmRectF;
//边缘字体
//privateBorderedTextmBorderedText;
//标题或名字
privateStringmTitle;
//概率
privatefloatmConfidence;
//矩形框corner的角度:直角、圆角
privateintmCornerAngle;
//直角默认
publicstaticfinalintRIGHT_CORNER=0;
//圆角
publicstaticfinalintROUND_CORNER=1;
//RemoveRect
privateintMODE;
privatestaticfinalintMODE_OUTSIDE=0x000000aa;/*170*/
privatestaticfinalintMODE_INSIDE=0x000000bb;/*187*/
privatestaticfinalintMODE_POINT=0X000000cc;/*204*/
privatestaticfinalintMODE_ILLEGAL=0X000000dd;/*221*/
privatefloatstartX;/*startXlocation*/
privatefloatstartY;/*startYlocation*/
privatefloatendX;/*endXlocation*/
privatefloatendY;/*endYlocation*/
privatefloatcurrentX;/*Xcoordinatevalueswhilefingerpress*/
privatefloatcurrentY;/*Ycoordinatevalueswhilefingerpress*/
privatefloatmemoryX;/*thelasttimethecoordinatevaluesofX*/
privatefloatmemoryY;/*thelasttimethecoordinatevaluesofY*/
privatefloatmCoverWidth;/*widthofselectionbox*/
privatefloatmCoverHeight;/*heightofselectionbox*/
privatestaticfinalintACCURACY=100;/*touchaccuracy*/
privateintpointPosition;/*vertexofarectangle*/
privatestaticfinalfloatminWidth=100.0f;/*theminimumwidthoftherectangle*/
privatestaticfinalfloatminHeight=200.0f;/*theminimumheightoftherectangle*/
privateonLocationListenermLocationListener;/*listentotheRect*/
privatestaticfinalfloatEDGE_WIDTH=1.8f;
publicMoveAndCropRectView(Contextcontext){
this(context,null);
}
publicMoveAndCropRectView(Contextcontext,@NullableAttributeSetattrs){
this(context,attrs,0);
}
publicMoveAndCropRectView(Contextcontext,@NullableAttributeSetattrs,intdefStyleAttr){
super(context,attrs,defStyleAttr);
initDatas(context);
}
privatevoidinitDatas(Contextcontext){
mPaint=newPaint();
mRectF=newRectF();
//画笔设置空心
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.WHITE);
mPaint.setStrokeWidth(2);
mPaint.setAntiAlias(true);
//floattextSizePx=TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
//18.0f,context.getResources().getDisplayMetrics());
//mBorderedText=newBorderedText(textSizePx);
currentX=0;
currentY=0;
}
privatebooleanfirstDraw=true;
@Override
protectedvoidonDraw(Canvascanvas){
super.onDraw(canvas);
//switch(mCornerAngle){
//caseRIGHT_CORNER://绘制损害框(直角矩形框)
//drawRect(canvas);
//break;
//caseROUND_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);/*top上边框-*/
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|*/
//绘制名称和概率
//finalStringlabelString=
//!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
publicbooleanonTouchEvent(MotionEventevent){
switch(event.getAction()){
caseMotionEvent.ACTION_DOWN:
memoryX=event.getX();
memoryY=event.getY();
checkMode(memoryX,memoryY);
break;
caseMotionEvent.ACTION_MOVE:{
currentX=event.getX();
currentY=event.getY();
switch(MODE){
caseMODE_ILLEGAL:
recoverFromIllegal(currentX,currentY);
postInvalidate();
break;
caseMODE_OUTSIDE:
//donothing;
break;
caseMODE_INSIDE://拖动
moveByTouch(currentX,currentY);
postInvalidate();
break;
default:
/*MODE_POINT*/
moveByPoint(currentX,currentY);
postInvalidate();
break;
}
}
break;
caseMotionEvent.ACTION_UP:
//mPaint.setColor(getContext().getResources().getColor(R.color.orange));
postInvalidate();
break;
default:
break;
}
returntrue;
}
/*点击顶点附近时的缩放处理*/
@SuppressWarnings("SuspiciousNameCombination")
privatevoidmoveByPoint(floatbx,floatby){
//LogUtils.d("moveByPoint");
switch(pointPosition){
case0:/*left-up*/
mCoverWidth=Math.abs(endX-bx);
mCoverHeight=Math.abs(endY-by);
//noinspectionSuspiciousNameCombination
if(!checkLegalRect(mCoverWidth,mCoverHeight)){
MODE=MODE_ILLEGAL;
}else{
refreshLocation(bx,by,endX,endY);
}
break;
case1:/*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;
case2:/*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;
case3:/*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;
}
}
/*刷新矩形的坐标*/
privatevoidrefreshLocation(floatisx,floatisy,floatiex,floatiey){
this.startX=isx;
this.startY=isy;
this.endX=iex;
this.endY=iey;
mCoverWidth=endX-startX;
mCoverHeight=endY-startY;
}
/*检测矩形是否达到最小值*/
privatebooleancheckLegalRect(floatcHeight,floatcWidth){
return(cHeight>minHeight&&cWidth>minWidth);
}
/*从非法状态恢复,这里处理的是达到最小值后能拉伸放大*/
privatevoidrecoverFromIllegal(floatrx,floatry){
if((rx>startX&&ry>startY)&&(rxstartX&&cxstartY&&cy=1920){
endX=1920;
startX=endX-mCoverWidth;
}
if(endY>=1080){
endY=1080;
startY=endY-mCoverHeight;
}
memoryX=mx;
memoryY=my;
}
/*判断点(inX,inY)是否靠近矩形的4个顶点*/
privateintnearbyPoint(floatfloatX,floatfloatY){
if((Math.abs(startX-floatX)<=ACCURACY&&(Math.abs(floatY-startY)<=ACCURACY))){/*left-upangle*/
pointPosition=0;
return0;
}
if((Math.abs(endX-floatX)<=ACCURACY&&(Math.abs(floatY-startY)<=ACCURACY))){/*right-upangle*/
pointPosition=1;
return1;
}
if((Math.abs(startX-floatX)<=ACCURACY&&(Math.abs(floatY-endY)<=ACCURACY))){/*left-downangle*/
pointPosition=2;
return2;
}
if((Math.abs(endX-floatX)<=ACCURACY&&(Math.abs(floatY-endY)<=ACCURACY))){/*right-downangle*/
pointPosition=3;
return3;
}
pointPosition=100;
return100;
}
//设置矩形框
publicvoidsetRectF(RectFrectf){
this.mRectF=rectf;
}
publicvoidsetTitle(Stringtitle){
mTitle=title;
}
publicvoidsetConfidence(floatconfidence){
mConfidence=confidence;
}
publicvoidsetCornerAngle(intcornerAngle){
this.mCornerAngle=cornerAngle;
}
//绘制损害框(直角矩形框)
privatevoiddrawRect(Canvascanvas){
canvas.drawRect(mRectF,mPaint);
//绘制名称和概率
//finalStringlabelString=
//!TextUtils.isEmpty(mTitle)
//?String.format("%s%.2f",mTitle,(100*mConfidence))
//:String.format("%.2f",(100*mConfidence));
//在直角矩形框上写字
//mBorderedText.drawText(canvas,
//mRectF.left,
//mRectF.top,labelString+"%",
//mPaint);
}
//绘制损害框(圆角矩形框)
privatevoiddrawRoundRect(Canvascanvas){
floatcornerSize=Math.min(mRectF.width(),mRectF.height())/8.0f;
canvas.drawRoundRect(mRectF,cornerSize,cornerSize,mPaint);
//绘制名称和概率
//finalStringlabelString=
//!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);
}
publicvoidsetLocationListener(onLocationListenermLocationListener){
this.mLocationListener=mLocationListener;
}
publicinterfaceonLocationListener{
voidlocationRect(floatstartX,floatstartY,floatendX,floatendY);
}
}
2.Activity里的应用
packagecom.xinrui.screenshot;
importandroid.app.Activity;
importandroid.graphics.RectF;
importandroid.os.Bundle;
importandroid.util.Log;
importandroid.widget.RelativeLayout;
importcom.xinrui.screenshot.view.CropRectView;
publicclassMainActivityextendsActivity{
privateRelativeLayoutmain_area;
CropRectViewcropRectView;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initview();
}
privatevoidinitview(){
main_area=(RelativeLayout)findViewById(R.id.main_area);
cropRectView=(CropRectView)findViewById(R.id.main_img);
RectFrectF=newRectF(660,240,1260,840);
cropRectView.setRectF(rectF);
cropRectView.setLocationListener(newCropRectView.onLocationListener(){
@Override
publicvoidlocationRect(floatstartX,floatstartY,floatendX,floatendY){
Log.e("MainActivity","[startX:("+startX+")--startY:("+startY+")--endX:("+endX+")--endY:("+endY+")]");
}
});
}
}
3.activity_main.xml
大功告成。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。