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多点触摸放大缩小图片的示例代码,希望对大家的学习有所帮助。