Android通过自定义ImageView控件实现图片的缩放和拖动的实现代码
概述:通过自定义ImageView控件,在xml布局里面调用自定的组件实现图片的缩放。
/**
*自定义的ImageView控制,可对图片进行多点触控缩放和拖动
*
*@authorqiuwanyong
*/
publicclassMyImageViewextendsImageView{
/**
*初始化状态常量
*/
publicstaticfinalintSTATUS_INIT=1;
/**
*图片放大状态常量
*/
publicstaticfinalintSTATUS_ZOOM_OUT=2;
/**
*图片缩小状态常量
*/
publicstaticfinalintSTATUS_ZOOM_IN=3;
/**
*图片拖动状态常量
*/
publicstaticfinalintSTATUS_MOVE=4;
/**
*用于对图片进行移动和缩放变换的矩阵
*/
privateMatrixmatrix=newMatrix();
/**
*待展示的Bitmap对象
*/
privateBitmapsourceBitmap;
/**
*记录当前操作的状态,可选值为STATUS_INIT、STATUS_ZOOM_OUT、STATUS_ZOOM_IN和STATUS_MOVE
*/
privateintcurrentStatus;
/**
*ZoomImageView控件的宽度
*/
privateintwidth;
/**
*ZoomImageView控件的高度
*/
privateintheight;
/**
*记录两指同时放在屏幕上时,中心点的横坐标值
*/
privatefloatcenterPointX;
/**
*记录两指同时放在屏幕上时,中心点的纵坐标值
*/
privatefloatcenterPointY;
/**
*记录当前图片的宽度,图片被缩放时,这个值会一起变动
*/
privatefloatcurrentBitmapWidth;
/**
*记录当前图片的高度,图片被缩放时,这个值会一起变动
*/
privatefloatcurrentBitmapHeight;
/**
*记录上次手指移动时的横坐标
*/
privatefloatlastXMove=-1;
/**
*记录上次手指移动时的纵坐标
*/
privatefloatlastYMove=-1;
/**
*记录手指在横坐标方向上的移动距离
*/
privatefloatmovedDistanceX;
/**
*记录手指在纵坐标方向上的移动距离
*/
privatefloatmovedDistanceY;
/**
*记录图片在矩阵上的横向偏移值
*/
privatefloattotalTranslateX;
/**
*记录图片在矩阵上的纵向偏移值
*/
privatefloattotalTranslateY;
/**
*记录图片在矩阵上的总缩放比例
*/
privatefloattotalRatio;
/**
*记录手指移动的距离所造成的缩放比例
*/
privatefloatscaledRatio;
/**
*记录图片初始化时的缩放比例
*/
privatefloatinitRatio;
/**
*记录上次两指之间的距离
*/
privatedoublelastFingerDis;
/**
*ZoomImageView构造函数,将当前操作状态设为STATUS_INIT。
*
*@paramcontext
*@paramattrs
*/
publicMyImageView(Contextcontext,AttributeSetattrs){
super(context,attrs);
currentStatus=STATUS_INIT;
}
/**
*将待展示的图片设置进来。
*
*@parambitmap
*待展示的Bitmap对象
*/
publicvoidsetImageBitmap(Bitmapbitmap){
sourceBitmap=bitmap;
invalidate();
}
@Override
protectedvoidonLayout(booleanchanged,intleft,inttop,intright,
intbottom){
super.onLayout(changed,left,top,right,bottom);
if(changed){
//分别获取到ZoomImageView的宽度和高度
width=getWidth();
height=getHeight();
}
}
@SuppressLint("NewApi")@Override
publicbooleanonTouchEvent(MotionEventevent){
if(initRatio==totalRatio){
getParent().requestDisallowInterceptTouchEvent(false);
}else{
getParent().requestDisallowInterceptTouchEvent(true);
}
switch(event.getActionMasked()){
caseMotionEvent.ACTION_POINTER_DOWN:
if(event.getPointerCount()==2){
//当有两个手指按在屏幕上时,计算两指之间的距离
lastFingerDis=distanceBetweenFingers(event);
}
break;
caseMotionEvent.ACTION_CANCEL:
caseMotionEvent.ACTION_MOVE:
if(event.getPointerCount()==1){
//只有单指按在屏幕上移动时,为拖动状态
floatxMove=event.getX();
floatyMove=event.getY();
if(lastXMove==-1&&lastYMove==-1){
lastXMove=xMove;
lastYMove=yMove;
}
currentStatus=STATUS_MOVE;
movedDistanceX=xMove-lastXMove;
movedDistanceY=yMove-lastYMove;
//进行边界检查,不允许将图片拖出边界
if(totalTranslateX+movedDistanceX>0){
movedDistanceX=0;
}elseif(width-(totalTranslateX+movedDistanceX)>currentBitmapWidth){
movedDistanceX=0;
}
if(totalTranslateY+movedDistanceY>0){
movedDistanceY=0;
}elseif(height-(totalTranslateY+movedDistanceY)>currentBitmapHeight){
movedDistanceY=0;
}
//调用onDraw()方法绘制图片
invalidate();
lastXMove=xMove;
lastYMove=yMove;
}elseif(event.getPointerCount()==2){
//有两个手指按在屏幕上移动时,为缩放状态
centerPointBetweenFingers(event);
doublefingerDis=distanceBetweenFingers(event);
if(fingerDis>lastFingerDis){
currentStatus=STATUS_ZOOM_OUT;
}else{
currentStatus=STATUS_ZOOM_IN;
}
//进行缩放倍数检查,最大只允许将图片放大4倍,最小可以缩小到初始化比例
if((currentStatus==STATUS_ZOOM_OUT&&totalRatio<4*initRatio)
||(currentStatus==STATUS_ZOOM_IN&&totalRatio>initRatio)){
scaledRatio=(float)(fingerDis/lastFingerDis);
totalRatio=totalRatio*scaledRatio;
if(totalRatio>4*initRatio){
totalRatio=4*initRatio;
}elseif(totalRatio<initRatio){
totalRatio=initRatio;
}
//调用onDraw()方法绘制图片
invalidate();
lastFingerDis=fingerDis;
}
}
break;
caseMotionEvent.ACTION_POINTER_UP:
if(event.getPointerCount()==2){
//手指离开屏幕时将临时值还原
lastXMove=-1;
lastYMove=-1;
}
break;
caseMotionEvent.ACTION_UP:
//手指离开屏幕时将临时值还原
lastXMove=-1;
lastYMove=-1;
break;
default:
break;
}
returntrue;
}
/**
*根据currentStatus的值来决定对图片进行什么样的绘制操作。
*/
@Override
protectedvoidonDraw(Canvascanvas){
super.onDraw(canvas);
switch(currentStatus){
caseSTATUS_ZOOM_OUT:
caseSTATUS_ZOOM_IN:
zoom(canvas);
break;
caseSTATUS_MOVE:
move(canvas);
break;
caseSTATUS_INIT:
initBitmap(canvas);
default:
if(sourceBitmap!=null){
canvas.drawBitmap(sourceBitmap,matrix,null);
}
break;
}
}
/**
*对图片进行缩放处理。
*
*@paramcanvas
*/
privatevoidzoom(Canvascanvas){
matrix.reset();
//将图片按总缩放比例进行缩放
matrix.postScale(totalRatio,totalRatio);
floatscaledWidth=sourceBitmap.getWidth()*totalRatio;
floatscaledHeight=sourceBitmap.getHeight()*totalRatio;
floattranslateX=0f;
floattranslateY=0f;
//如果当前图片宽度小于屏幕宽度,则按屏幕中心的横坐标进行水平缩放。否则按两指的中心点的横坐标进行水平缩放
if(currentBitmapWidth<width){
translateX=(width-scaledWidth)/2f;
}else{
translateX=totalTranslateX*scaledRatio+centerPointX
*(1-scaledRatio);
//进行边界检查,保证图片缩放后在水平方向上不会偏移出屏幕
if(translateX>0){
translateX=0;
}elseif(width-translateX>scaledWidth){
translateX=width-scaledWidth;
}
}
//如果当前图片高度小于屏幕高度,则按屏幕中心的纵坐标进行垂直缩放。否则按两指的中心点的纵坐标进行垂直缩放
if(currentBitmapHeight<height){
translateY=(height-scaledHeight)/2f;
}else{
translateY=totalTranslateY*scaledRatio+centerPointY
*(1-scaledRatio);
//进行边界检查,保证图片缩放后在垂直方向上不会偏移出屏幕
if(translateY>0){
translateY=0;
}elseif(height-translateY>scaledHeight){
translateY=height-scaledHeight;
}
}
//缩放后对图片进行偏移,以保证缩放后中心点位置不变
matrix.postTranslate(translateX,translateY);
totalTranslateX=translateX;
totalTranslateY=translateY;
currentBitmapWidth=scaledWidth;
currentBitmapHeight=scaledHeight;
canvas.drawBitmap(sourceBitmap,matrix,null);
}
/**
*对图片进行平移处理
*
*@paramcanvas
*/
privatevoidmove(Canvascanvas){
matrix.reset();
//根据手指移动的距离计算出总偏移值
floattranslateX=totalTranslateX+movedDistanceX;
floattranslateY=totalTranslateY+movedDistanceY;
//先按照已有的缩放比例对图片进行缩放
matrix.postScale(totalRatio,totalRatio);
//再根据移动距离进行偏移
matrix.postTranslate(translateX,translateY);
totalTranslateX=translateX;
totalTranslateY=translateY;
canvas.drawBitmap(sourceBitmap,matrix,null);
}
/**
*对图片进行初始化操作,包括让图片居中,以及当图片大于屏幕宽高时对图片进行压缩。
*
*@paramcanvas
*/
privatevoidinitBitmap(Canvascanvas){
if(sourceBitmap!=null){
matrix.reset();
intbitmapWidth=sourceBitmap.getWidth();
intbitmapHeight=sourceBitmap.getHeight();
if(bitmapWidth>width||bitmapHeight>height){
if(bitmapWidth-width>bitmapHeight-height){
//当图片宽度大于屏幕宽度时,将图片等比例压缩,使它可以完全显示出来
floatratio=width/(bitmapWidth*1.0f);
matrix.postScale(ratio,ratio);
floattranslateY=(height-(bitmapHeight*ratio))/2f;
//在纵坐标方向上进行偏移,以保证图片居中显示
matrix.postTranslate(0,translateY);
totalTranslateY=translateY;
totalRatio=initRatio=ratio;
}else{
//当图片高度大于屏幕高度时,将图片等比例压缩,使它可以完全显示出来
floatratio=height/(bitmapHeight*1.0f);
matrix.postScale(ratio,ratio);
floattranslateX=(width-(bitmapWidth*ratio))/2f;
//在横坐标方向上进行偏移,以保证图片居中显示
matrix.postTranslate(translateX,0);
totalTranslateX=translateX;
totalRatio=initRatio=ratio;
}
currentBitmapWidth=bitmapWidth*initRatio;
currentBitmapHeight=bitmapHeight*initRatio;
}else{
//当图片的宽高都小于屏幕宽高时,直接让图片居中显示
floattranslateX=(width-sourceBitmap.getWidth())/2f;
floattranslateY=(height-sourceBitmap.getHeight())/2f;
matrix.postTranslate(translateX,translateY);
totalTranslateX=translateX;
totalTranslateY=translateY;
totalRatio=initRatio=1f;
currentBitmapWidth=bitmapWidth;
currentBitmapHeight=bitmapHeight;
}
canvas.drawBitmap(sourceBitmap,matrix,null);
}
}
/**
*计算两个手指之间的距离。
*
*@paramevent
*@return两个手指之间的距离
*/
@SuppressLint("NewApi")privatedoubledistanceBetweenFingers(MotionEventevent){
floatdisX=Math.abs(event.getX(0)-event.getX(1));
floatdisY=Math.abs(event.getY(0)-event.getY(1));
returnMath.sqrt(disX*disX+disY*disY);
}
/**
*计算两个手指之间中心点的坐标。
*
*@paramevent
*/
@SuppressLint("NewApi")privatevoidcenterPointBetweenFingers(MotionEventevent){
floatxPoint0=event.getX(0);
floatyPoint0=event.getY(0);
floatxPoint1=event.getX(1);
floatyPoint1=event.getY(1);
centerPointX=(xPoint0+xPoint1)/2;
centerPointY=(yPoint0+yPoint1)/2;
}
}
布局中调用
以上所述是小编给大家介绍的Android通过自定义ImageView控件实现图片的缩放和拖动的实现代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!