Ultimate Edition
Package Com.zhy.view;import Android.annotation.suppresslint;import Android.content.context;import Android.graphics.matrix;import Android.graphics.rectf;import Android.graphics.drawable.drawable;import Android.util.attributeset;import Android.util.log;import Android.view.gesturedetector;import Android.view.motionevent;import Android.view.scalegesturedetector;import Android.view.gesturedetector.simpleongesturelistener;import Android.view.scalegesturedetector.onscalegesturelistener;import Android.view.view;import Android.view.view.ontouchlistener;import Android.view.viewtreeobserver;import android.widget.ImageView;/** * * @ Author Zhy * Blog address: http://blog.csdn.net/lmj623565791 */public class Zoomimageview extends ImageView implements Onscalegesturelistener,ontouchlistener, viewtreeobserver.ongloballayoutlistener{private static final String TAG = ZoomImageView.class.getSimpleName ();p ublic static final float Scale_max = 4.0f;private static final float Scale_mid = 2.0f /** * When initializing the zoom ratio, if the picture is wide or tallOn the screen, this value will be less than 0 */private float Initscale = 1.0f;private Boolean once = true;/** * For storing 9 values of the Matrix */private final float[] Matrixval ues = new float[9];/** * Zoom gesture detection */private scalegesturedetector mscalegesturedetector = null;private final Matrix mscalema Trix = new Matrix ();/** * for double-click Detection */private gesturedetector mgesturedetector;private boolean isautoscale;private int MTouch slop;private Float mlastx;private float mlasty;private boolean iscandrag;private int Lastpointercount;private Boolean Ischecktopandbottom = true;private Boolean ischeckleftandright = True;public Zoomimageview (context context) {This ( context, NULL);} Public Zoomimageview (context context, AttributeSet Attrs) {Super (context, attrs); Super.setscaletype (Scaletype.matrix ); mgesturedetector = new Gesturedetector (context,new Simpleongesturelistener () {@Overridepublic Boolean Ondoubletap ( Motionevent e) {if (Isautoscale = = true) return true;float x = E.getx (); Float y = e.gety (); LOG.E ("Doubletap", Getscale () + "," + Initscale); if (Getscale () < Scale_mid) {ZoomImageView.this.postDelayed (new autoscalerunnable (Scale_mid, x, y), +); Isautoscale = true;} else if ( Getscale () >= scale_mid&& Getscale () < Scale_max) {ZoomImageView.this.postDelayed (new autoscalerunnable (Scale_max, x, y), +); Isautoscale = true;} Else{zoomimageview.this.postdelayed (New Autoscalerunnable (Initscale, x, y), +); Isautoscale = true;} return true;}}); Mscalegesturedetector = new Scalegesturedetector (context, this); This.setontouchlistener (this);} /** * Auto-scaling Tasks * * @author Zhy * */private class Autoscalerunnable implements runnable{static final float bigger = 1.07f; Static final float SMALLER = 0.93f;private float mtargetscale;private float tmpscale;/** * Zoom Center */private float X;private FLOAT y;/** * Incoming target zoom value, according to the target value and the current value, determine whether to enlarge or reduce the * @param targetscale */public autoscalerunnable (float targetscale, float x, Float y) {This.mtargetscale = Targetscale;this.x = X;this.y = Y;if (Getscale () < Mtargetscale) {Tmpscale = BIGGER;} else {Tmpscale = SMALLER;}}@Overridepublic void Run () {//scaled Mscalematrix.postscale (Tmpscale, Tmpscale, x, y); Checkborderandcenterwhenscale (); Setimagematrix (Mscalematrix); final float Currentscale = Getscale ();//If the value is within the legal range, continue scaling if ((Tmpscale > 1f) && ( Currentscale < Mtargetscale) | | ((Tmpscale < 1f) && (Mtargetscale < Currentscale))) {ZoomImageView.this.postDelayed (this, 16);} else//set to the target scale {final float Deltascale = Mtargetscale/currentscale;mscalematrix.postscale (Deltascale, Deltascale, X , y); Checkborderandcenterwhenscale (); Setimagematrix (Mscalematrix); isautoscale = false;}}} @SuppressLint ("Newapi") @Overridepublic boolean Onscale (Scalegesturedetector detector) {Float scale = Getscale (); float Scalefactor = Detector.getscalefactor (); if (getdrawable () = = NULL) return true;/** * Zoom range Control */if (Scale < Scale_max &A mp;& scalefactor > 1.0f) | | (Scale > Initscale && scalefactor < 1.0f)) {/** * Maximum minimum value */if (scalefactor * Scale < Initscale) {scalefactor = Initscale/scale;} if (Scalefactor * scale > Scale_max) {scalefactor = Scale_max/scale;} /** * Set Scaling */mscalematrix.postscale (Scalefactor, Scalefactor,detector.getfocusx (), detector.getfocusy ()); Checkborderandcenterwhenscale (); Setimagematrix (Mscalematrix);} return true;} /** * When zooming, the control of the picture display range */private void Checkborderandcenterwhenscale () {RECTF rect = GETMATRIXRECTF (); Float deltax = 0;floa T DeltaY = 0;int width = getwidth (); int height = getheight ();//If the width or height is greater than the screen, then the control range if (Rect.width () >= width) {if (rect.left > 0) {deltax =-rect.left;} if (Rect.right < width) {deltax = Width-rect.right;}} if (rect.height () >= height) {if (Rect.top > 0) {deltay =-rect.top;} if (Rect.bottom < height) {deltay = Height-rect.bottom;}} If the width or height is less than the screen, let it be centered if (Rect.width () < width) {deltax = width * 0.5f-rect.right + 0.5f * rect.width ();} if (Rect.height () < height) {deltay = height * 0.5f-rect.bottom + 0.5f * rect.height ();} LOG.E (TAG, "deltax =" + DeltaX + ", DeltaY =" + DeltaY); Mscalematrix.posttRanslate (DeltaX, DeltaY);} /** * Gets the range of images according to the matrix of the current picture * * @return */private RECTF GETMATRIXRECTF () {Matrix Matrix = Mscalematrix; RECTF rect = new RECTF ();D rawable d = getdrawable (), if (null! = d) {rect.set (0, 0, d.getintrinsicwidth (), D.getintrinsichei Ght ()); Matrix.maprect (rect);} return rect; @Overridepublic Boolean onscalebegin (Scalegesturedetector detector) {return true;} @Overridepublic void Onscaleend (Scalegesturedetector detector) {} @Overridepublic boolean OnTouch (View V, motionevent Event) {if (Mgesturedetector.ontouchevent (event)) return True;mscalegesturedetector.ontouchevent (event); float x = 0, y = 0;//Gets the number of touch points final int pointercount = Event.getpointercount ();//Gets the X and y mean values for multiple touch points for (int i = 0; i < Pointercount; i++) { x + = Event.getx (i); y + = event.gety (i); x = X/pointercount;y = y/pointercount;/** * Resets mlasx, mlasty */if (pointercount! = lastpointercount) Whenever the touch point changes, IsCanD Rag = False;mlastx = X;mlasty = y;} Lastpointercount = Pointercount; RECTF RECTF = GETMATRIXRECTF (); switch (event. Getaction ()) {Case MotionEvent.ACTION_DOWN:if (rectf.width () > getwidth () | | rectf.height () > GetHeight ()) { GetParent (). Requestdisallowintercepttouchevent (True); Break;case MotionEvent.ACTION_MOVE:if (Rectf.width () > getwidth () | | rectf.height () > GetHeight ()) {getParent (). Requestdisallowintercepttouchevent (TRUE);} LOG.E (TAG, "action_move"); float dx = x-mlastx;float dy = y-mlasty;if (!iscandrag) {Iscandrag = Iscandrag (dx, dy);} if (Iscandrag) {if (getdrawable () = null) {//if (GETMATRIXRECTF (). left = = 0 && dx > 0)//{//GetParent (). reques Tdisallowintercepttouchevent (false);//}////if (GETMATRIXRECTF (). Right = = getwidth () && DX < 0)//{//Getpare NT (). Requestdisallowintercepttouchevent (false);//}ischeckleftandright = Ischecktopandbottom = true;//If the width is less than the screen width, Then disable left and right moves if (Rectf.width () < GetWidth ()) {dx = 0;ischeckleftandright = false;} If the height of the screen is highly cloudy, it is forbidden to move up or down if (Rectf.height () < GetHeight ()) {dy = 0;ischecktopandbottom = false;} Mscalematrix.posttranslate (dx, dy); Checkmatrixbounds (); Setimagematrix (Mscalematrix);}} MLASTX = X;mlasty = Y;break;case MotionEvent.ACTION_UP:case motionevent.action_cancel:log.e (TAG, "action_up"); Lastpointercount = 0;break;} return true;} /** * Get Current ZOOM ratio * * @return */public final float Getscale () {mscalematrix.getvalues (matrixvalues); return Matrixvalues[mat Rix. MSCALE_X];} @Overrideprotected void Onattachedtowindow () {Super.onattachedtowindow (); Getviewtreeobserver (). Addongloballayoutlistener (this);} @SuppressWarnings ("deprecation") @Overrideprotected void Ondetachedfromwindow () {Super.ondetachedfromwindow (); Getviewtreeobserver (). Removeglobalonlayoutlistener (this);} @Overridepublic void Ongloballayout () {if (once) {drawable d = getdrawable (); if (d = = null) return; LOG.E (TAG, d.getintrinsicwidth () + "," + d.getintrinsicheight ()); int width = getwidth (); int height = getheight ();//Get Picture The width and height of the int dw = D.getintrinsicwidth (); int dh = d.getintrinsicheight (); float scale = 1.0f;//If the picture is wide or tall on the screen, zoom to the width or height of the screen if (DW & Gt Width && DH <= height) {scale = width * 1.0F/DW;} if (DH > Height && DW <= width) {scale = height * 1.0F/DH;} If the width and height are larger than the screen, let it fit the screen size proportionally if (DW > Width && dh > height) {scale = Math.min (width * 1.0f/dw, Height * 1.0f /DH);} Initscale = scale; LOG.E (TAG, "Initscale =" + Initscale); Mscalematrix.posttranslate ((WIDTH-DW)/2, (HEIGHT-DH)/2); MSCALEMATRIX.POSTSC Ale (scale, scale, getwidth ()/2,getheight ()/2),//Picture moved to Screen center Setimagematrix (mscalematrix); once = false;}} /** * When moving, the boundary is judged, the main judgment is that the width or height is greater than the screen */private void Checkmatrixbounds () {RECTF rect = GETMATRIXRECTF (); float deltax = 0, DeltaY = 0;final float viewwidth = getwidth (); final float viewheight = getheight ();//Determines whether the picture is displayed beyond the screen boundary if it is moved or scaled if (Rect.top > 0 & ;& ischecktopandbottom) {deltay =-rect.top;} if (Rect.bottom < viewheight && ischecktopandbottom) {deltay = Viewheight-rect.bottom;} if (Rect.left > 0 && ischeckleftandright) {deltax =-rect.left;} if (Rect.right < Viewwidth && isCheckleftandright) {deltax = Viewwidth-rect.right;} Mscalematrix.posttranslate (DeltaX, DeltaY);} /** * is the push behavior * * @param dx * @param dy * @return */private boolean iscandrag (float dx, float dy) {return math.sqrt (DX * DX) + (dy * dy)) >= mtouchslop;}}
Layout file: Activity_main.xml
<relativelayout xmlns:android= "http://schemas.android.com/apk/res/android" xmlns:tools= "http// Schemas.android.com/tools " android:layout_width=" match_parent " android:layout_height=" Match_parent " > <com.zhy.view.zoomimageview android:layout_width= "fill_parent" android:layout_height= "fill _parent " android:scaletype=" Matrix " android:src=" @drawable/tbug "/></relativelayout>
Vp.xml
<relativelayout xmlns:android= "http://schemas.android.com/apk/res/android" xmlns:tools= "http// Schemas.android.com/tools " android:layout_width=" match_parent " android:layout_height=" Match_parent " > <android.support.v4.view.viewpager android:id= "@+id/id_viewpager" android:layout_width= " Fill_parent " android:layout_height=" fill_parent "> </android.support.v4.view.viewpager></ Relativelayout>
Use in activity:
Package Com.zhy.zhy_scalegesturedetector02;import Android.app.activity;import Android.os.bundle;import Android.support.v4.view.pageradapter;import Android.support.v4.view.viewpager;import Android.view.View;import Android.view.viewgroup;import Android.widget.imageview;import Com.zhy.view.zoomimageview;public class MainActivity Extends Activity{private viewpager mviewpager;private int[] Mimgs = new int[] {r.drawable.tbug, r.drawable.a,r.drawable. XX};p rivate imageview[] mimageviews = new Imageview[mimgs.length]; @Overrideprotected void OnCreate (Bundle Savedinstancestate) {super.oncreate (savedinstancestate); Setcontentview (R.LAYOUT.VP); MViewPager = (ViewPager) Findviewbyid (R.id.id_viewpager); Mviewpager.setadapter (new Pageradapter () {@Overridepublic Object Instantiateitem ( ViewGroup container, int position) {Zoomimageview ImageView = new Zoomimageview (Getapplicationcontext ()); Imageview.setimageresource (Mimgs[position]); Container.addview (ImageView); mimageviews[position] = ImageView; Return ImagevIew;} @Overridepublic void Destroyitem (ViewGroup container, int position,object Object) {Container.removeview (mimageviews[ Position]);} @Overridepublic boolean isviewfromobject (View arg0, Object arg1) {return arg0 = = arg1;} @Overridepublic int GetCount () {return mimgs.length;}});}}
Viewpager Picture preview Image Zoom out, move, toggle (fourth lesson) it's over.