Android手势滑动实现两点触摸缩放图片
学习安卓手势滑动,多点触摸放大缩小图片,分享给大家供大家参考,具体代码如下
1.布局文件如下main.xml
<?xmlversion="1.0"encoding="utf-8"?> <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <!--引用自定义控件--> <com.ymw.zoomimage.ZoomImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="wrap_content"> </com.ymw.zoomimage.ZoomImageView> </LinearLayout>
2.自定义缩放图片控件ZoomImageView.java代码:
packagecom.ymw.zoomimage;
importjava.util.Observable;
importjava.util.Observer;
importandroid.content.Context;
importandroid.graphics.Bitmap;
importandroid.graphics.Canvas;
importandroid.graphics.Paint;
importandroid.graphics.Rect;
importandroid.util.AttributeSet;
importandroid.util.Log;
importandroid.view.MotionEvent;
importandroid.view.View;
publicclassZoomImageViewextendsViewimplementsObserver{
/**Paintobjectusedwhendrawingbitmap.*/
privatefinalPaintmPaint=newPaint(Paint.FILTER_BITMAP_FLAG);
/**Rectangleused(andre-used)forcroppingsourceimage.*/
privatefinalRectmRectSrc=newRect();
/**Rectangleused(andre-used)forspecifyingdrawingareaoncanvas.*/
privatefinalRectmRectDst=newRect();
/**Objectholdingaspectquotient*/
privatefinalAspectQuotientmAspectQuotient=newAspectQuotient();
/**Thebitmapthatwe'rezoomingin,anddrawingonthescreen.*/
privateBitmapmBitmap;
/**Stateofthezoom.*/
privateZoomStatemState;
privateBasicZoomControlmZoomControl;
privateBasicZoomListenermZoomListener;
publicZoomImageView(Contextcontext,AttributeSetattrs){
super(context,attrs);
mZoomControl=newBasicZoomControl();
mZoomListener=newBasicZoomListener();
mZoomListener.setZoomControl(mZoomControl);
setZoomState(mZoomControl.getZoomState());
setOnTouchListener(mZoomListener);
mZoomControl.setAspectQuotient(getAspectQuotient());
}
publicvoidzoomImage(floatf,floatx,floaty){
mZoomControl.zoom(f,x,y);
}
publicvoidsetImage(Bitmapbitmap){
mBitmap=bitmap;
mAspectQuotient.updateAspectQuotient(getWidth(),getHeight(),
mBitmap.getWidth(),mBitmap.getHeight());
mAspectQuotient.notifyObservers();
invalidate();
}
privatevoidsetZoomState(ZoomStatestate){
if(mState!=null){
mState.deleteObserver(this);
}
mState=state;
mState.addObserver(this);
invalidate();
}
privateAspectQuotientgetAspectQuotient(){
returnmAspectQuotient;
}
@Override
protectedvoidonDraw(Canvascanvas){
if(mBitmap!=null&&mState!=null){
Log.d("ZoomImageView","OnDraw");
finalfloataspectQuotient=mAspectQuotient.get();
finalintviewWidth=getWidth();
finalintviewHeight=getHeight();
finalintbitmapWidth=mBitmap.getWidth();
finalintbitmapHeight=mBitmap.getHeight();
Log.d("ZoomImageView","viewWidth="+viewWidth);
Log.d("ZoomImageView","viewHeight="+viewHeight);
Log.d("ZoomImageView","bitmapWidth="+bitmapWidth);
Log.d("ZoomImageView","bitmapHeight="+bitmapHeight);
finalfloatpanX=mState.getPanX();
finalfloatpanY=mState.getPanY();
finalfloatzoomX=mState.getZoomX(aspectQuotient)*viewWidth
/bitmapWidth;
finalfloatzoomY=mState.getZoomY(aspectQuotient)*viewHeight
/bitmapHeight;
//Setupsourceanddestinationrectangles
mRectSrc.left=(int)(panX*bitmapWidth-viewWidth/(zoomX*2));
mRectSrc.top=(int)(panY*bitmapHeight-viewHeight
/(zoomY*2));
mRectSrc.right=(int)(mRectSrc.left+viewWidth/zoomX);
mRectSrc.bottom=(int)(mRectSrc.top+viewHeight/zoomY);
//mRectDst.left=getLeft();
mRectDst.left=0;
mRectDst.top=0;
//mRectDst.right=getRight();
mRectDst.right=getWidth();
mRectDst.bottom=getHeight();
//Adjustsourcerectanglesothatitfitswithinthesourceimage.
if(mRectSrc.left<0){
mRectDst.left+=-mRectSrc.left*zoomX;
mRectSrc.left=0;
}
if(mRectSrc.right>bitmapWidth){
mRectDst.right-=(mRectSrc.right-bitmapWidth)*zoomX;
mRectSrc.right=bitmapWidth;
}
if(mRectSrc.top<0){
mRectDst.top+=-mRectSrc.top*zoomY;
mRectSrc.top=0;
}
if(mRectSrc.bottom>bitmapHeight){
mRectDst.bottom-=(mRectSrc.bottom-bitmapHeight)*zoomY;
mRectSrc.bottom=bitmapHeight;
}
mRectDst.left=0;
mRectDst.top=0;
mRectDst.right=viewWidth;
mRectDst.bottom=viewHeight;
Log.d("ZoomImageView","mRectSrc.top"+mRectSrc.top);
Log.d("ZoomImageView","mRectSrc.bottom"+mRectSrc.bottom);
Log.d("ZoomImageView","mRectSrc.left"+mRectSrc.left);
Log.d("ZoomImageView","mRectSrc.right"+mRectSrc.right);
Log.d("ZoomImageView","mRectDst.top"+mRectDst.top);
Log.d("ZoomImageView","mRectDst.bottom"+mRectDst.bottom);
Log.d("ZoomImageView","mRectDst.left"+mRectDst.left);
Log.d("ZoomImageView","mRectDst.right"+mRectDst.right);
canvas.drawBitmap(mBitmap,mRectSrc,mRectDst,mPaint);
}
}
@Override
protectedvoidonLayout(booleanchanged,intleft,inttop,intright,
intbottom){
super.onLayout(changed,left,top,right,bottom);
mAspectQuotient.updateAspectQuotient(right-left,bottom-top,
mBitmap.getWidth(),mBitmap.getHeight());
mAspectQuotient.notifyObservers();
}
@Override
publicvoidupdate(Observableobservable,Objectdata){
invalidate();
}
privateclassBasicZoomListenerimplementsView.OnTouchListener{
/**Zoomcontroltomanipulate*/
privateBasicZoomControlmZoomControl;
privatefloatmFirstX=-1;
privatefloatmFirstY=-1;
privatefloatmSecondX=-1;
privatefloatmSecondY=-1;
privateintmOldCounts=0;
/**
*Setsthezoomcontroltomanipulate
*
*@paramcontrol
*Zoomcontrol
*/
publicvoidsetZoomControl(BasicZoomControlcontrol){
mZoomControl=control;
}
publicbooleanonTouch(Viewv,MotionEventevent){
switch(event.getAction()){
caseMotionEvent.ACTION_DOWN:
mOldCounts=1;
mFirstX=event.getX();
mFirstY=event.getY();
break;
caseMotionEvent.ACTION_MOVE:{
floatfFirstX=event.getX();
floatfFirstY=event.getY();
intnCounts=event.getPointerCount();
if(1==nCounts){
mOldCounts=1;
floatdx=(fFirstX-mFirstX)/v.getWidth();
floatdy=(fFirstY-mFirstY)/v.getHeight();
mZoomControl.pan(-dx,-dy);
}elseif(1==mOldCounts){
mSecondX=event.getX(event.getPointerId(nCounts-1));
mSecondY=event.getY(event.getPointerId(nCounts-1));
mOldCounts=nCounts;
}else{
floatfSecondX=event
.getX(event.getPointerId(nCounts-1));
floatfSecondY=event
.getY(event.getPointerId(nCounts-1));
doublenLengthOld=getLength(mFirstX,mFirstY,mSecondX,
mSecondY);
doublenLengthNow=getLength(fFirstX,fFirstY,fSecondX,
fSecondY);
floatd=(float)((nLengthNow-nLengthOld)/v.getWidth());
mZoomControl.zoom((float)Math.pow(20,d),
((fFirstX+fSecondX)/2/v.getWidth()),
((fFirstY+fSecondY)/2/v.getHeight()));
mSecondX=fSecondX;
mSecondY=fSecondY;
}
mFirstX=fFirstX;
mFirstY=fFirstY;
break;
}
}
returntrue;
}
privatedoublegetLength(floatx1,floaty1,floatx2,floaty2){
returnMath.sqrt(Math.pow(x1-x2,2)+Math.pow(y1-y2,2));
}
}
privateclassBasicZoomControlimplementsObserver{
/**Minimumzoomlevellimit*/
privatestaticfinalfloatMIN_ZOOM=1;
/**Maximumzoomlevellimit*/
privatestaticfinalfloatMAX_ZOOM=16;
/**Zoomstateundercontrol*/
privatefinalZoomStatemState=newZoomState();
/**Objectholdingaspectquotientofviewandcontent*/
privateAspectQuotientmAspectQuotient;
/**
*Setreferenceobjectholdingaspectquotient
*
*@paramaspectQuotient
*Objectholdingaspectquotient
*/
publicvoidsetAspectQuotient(AspectQuotientaspectQuotient){
if(mAspectQuotient!=null){
mAspectQuotient.deleteObserver(this);
}
mAspectQuotient=aspectQuotient;
mAspectQuotient.addObserver(this);
}
/**
*Getzoomstatebeingcontrolled
*
*@returnThezoomstate
*/
publicZoomStategetZoomState(){
returnmState;
}
/**
*Zoom
*
*@paramf
*Factorofzoomtoapply
*@paramx
*X-coordinateofinvariantposition
*@paramy
*Y-coordinateofinvariantposition
*/
publicvoidzoom(floatf,floatx,floaty){
//Log.d("Zoom","zoomf="+f);
finalfloataspectQuotient=mAspectQuotient.get();
finalfloatprevZoomX=mState.getZoomX(aspectQuotient);
finalfloatprevZoomY=mState.getZoomY(aspectQuotient);
mState.setZoom(mState.getZoom()*f);
limitZoom();
finalfloatnewZoomX=mState.getZoomX(aspectQuotient);
finalfloatnewZoomY=mState.getZoomY(aspectQuotient);
//Pantokeepxandycoordinateinvariant
mState.setPanX(mState.getPanX()+(x-.5f)
*(1f/prevZoomX-1f/newZoomX));
mState.setPanY(mState.getPanY()+(y-.5f)
*(1f/prevZoomY-1f/newZoomY));
limitPan();
mState.notifyObservers();
}
/**
*Pan
*
*@paramdx
*Amounttopaninx-dimension
*@paramdy
*Amounttopaniny-dimension
*/
publicvoidpan(floatdx,floatdy){
finalfloataspectQuotient=mAspectQuotient.get();
mState.setPanX(mState.getPanX()+dx
/mState.getZoomX(aspectQuotient));
mState.setPanY(mState.getPanY()+dy
/mState.getZoomY(aspectQuotient));
limitPan();
mState.notifyObservers();
}
/**
*Helpfunctiontofigureoutmaxdeltaofpanfromcenterposition.
*
*@paramzoom
*Zoomvalue
*@returnMaxdeltaofpan
*/
privatefloatgetMaxPanDelta(floatzoom){
returnMath.max(0f,.5f*((zoom-1)/zoom));
}
/**
*Forcezoomtostaywithinlimits
*/
privatevoidlimitZoom(){
if(mState.getZoom()<MIN_ZOOM){
mState.setZoom(MIN_ZOOM);
}elseif(mState.getZoom()>MAX_ZOOM){
mState.setZoom(MAX_ZOOM);
}
}
/**
*Forcepantostaywithinlimits
*/
privatevoidlimitPan(){
finalfloataspectQuotient=mAspectQuotient.get();
finalfloatzoomX=mState.getZoomX(aspectQuotient);
finalfloatzoomY=mState.getZoomY(aspectQuotient);
finalfloatpanMinX=.5f-getMaxPanDelta(zoomX);
finalfloatpanMaxX=.5f+getMaxPanDelta(zoomX);
finalfloatpanMinY=.5f-getMaxPanDelta(zoomY);
finalfloatpanMaxY=.5f+getMaxPanDelta(zoomY);
if(mState.getPanX()<panMinX){
mState.setPanX(panMinX);
}
if(mState.getPanX()>panMaxX){
mState.setPanX(panMaxX);
}
if(mState.getPanY()<panMinY){
mState.setPanY(panMinY);
}
if(mState.getPanY()>panMaxY){
mState.setPanY(panMaxY);
}
}
//Observableinterfaceimplementation
publicvoidupdate(Observableobservable,Objectdata){
limitZoom();
limitPan();
}
}
privateclassAspectQuotientextendsObservable{
/**
*Aspectquotient
*/
privatefloatmAspectQuotient;
//Publicmethods
/**
*Getsaspectquotient
*
*@returnTheaspectquotient
*/
publicfloatget(){
returnmAspectQuotient;
}
/**
*Updatesandrecalculatesaspectquotientbasedonsuppliedviewand
*contentdimensions.
*
*@paramviewWidth
*Widthofview
*@paramviewHeight
*Heightofview
*@paramcontentWidth
*Widthofcontent
*@paramcontentHeight
*Heightofcontent
*/
publicvoidupdateAspectQuotient(floatviewWidth,floatviewHeight,
floatcontentWidth,floatcontentHeight){
finalfloataspectQuotient=(contentWidth/contentHeight)
/(viewWidth/viewHeight);
if(aspectQuotient!=mAspectQuotient){
mAspectQuotient=aspectQuotient;
setChanged();
}
}
}
privateclassZoomStateextendsObservable{
/**
*ZoomlevelAvalueof1.0meansthecontentfitstheview.
*/
privatefloatmZoom;
/**
*Panpositionx-coordinateX-coordinateofzoomwindowcenter
*position,relativetothewidthofthecontent.
*/
privatefloatmPanX;
/**
*Panpositiony-coordinateY-coordinateofzoomwindowcenter
*position,relativetotheheightofthecontent.
*/
privatefloatmPanY;
//Publicmethods
/**
*Getcurrentx-pan
*
*@returncurrentx-pan
*/
publicfloatgetPanX(){
returnmPanX;
}
/**
*Getcurrenty-pan
*
*@returnCurrenty-pan
*/
publicfloatgetPanY(){
returnmPanY;
}
/**
*Getcurrentzoomvalue
*
*@returnCurrentzoomvalue
*/
publicfloatgetZoom(){
returnmZoom;
}
/**
*Helpfunctionforcalculatingcurrentzoomvalueinx-dimension
*
*@paramaspectQuotient
*(Aspectratiocontent)/(Aspectratioview)
*@returnCurrentzoomvalueinx-dimension
*/
publicfloatgetZoomX(floataspectQuotient){
returnMath.min(mZoom,mZoom*aspectQuotient);
}
/**
*Helpfunctionforcalculatingcurrentzoomvalueiny-dimension
*
*@paramaspectQuotient
*(Aspectratiocontent)/(Aspectratioview)
*@returnCurrentzoomvalueiny-dimension
*/
publicfloatgetZoomY(floataspectQuotient){
returnMath.min(mZoom,mZoom/aspectQuotient);
}
/**
*Setpan-x
*
*@parampanX
*Pan-xvaluetoset
*/
publicvoidsetPanX(floatpanX){
if(panX!=mPanX){
mPanX=panX;
setChanged();
}
}
/**
*Setpan-y
*
*@parampanY
*Pan-yvaluetoset
*/
publicvoidsetPanY(floatpanY){
if(panY!=mPanY){
mPanY=panY;
setChanged();
}
}
/**
*Setzoom
*
*@paramzoom
*Zoomvaluetoset
*/
publicvoidsetZoom(floatzoom){
if(zoom!=mZoom){
mZoom=zoom;
setChanged();
}
}
}
}
3.工程主文件MainActivity.java代码:
packagecom.ymw.zoomimage;
importandroid.app.Activity;
importandroid.graphics.Bitmap;
importandroid.graphics.BitmapFactory;
importandroid.os.Bundle;
publicclassMainActivityextendsActivity{
privateZoomImageViewzoomImg;
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
zoomImg=(ZoomImageView)findViewById(R.id.image);
Bitmapbitmap=BitmapFactory.decodeResource(this.getResources(),
R.drawable.a);
zoomImg.setImage(bitmap);
}
}
以上就是Android多点触摸放大缩小图片的示例代码,希望对大家的学习有所帮助。