Android gesture detection to create a picture preview that supports zoom panning (bottom)

Source: Internet
Author: User
Tags gety

Reprint please indicate source: http://blog.csdn.net/lmj623565791/article/details/39480503, this article from: "Zhang Hongyang's Blog"

The previous article has been taken to achieve the freedom of zooming in and out of the picture, a brief introduction of the next matrix; for details, please refer to: Android gesture detection to create a picture preview that supports zoom panning (top); This article continues to improve our imageview~~

First add the enlarged move ~ ~

1. Freedom to move

We are inside the ontouchevent, plus the moving code, of course, must be long or wider than the screen to be able to move ~ ~ ~

@Overridepublic boolean OnTouch (View V, motionevent event) {mscalegesturedetector.ontouchevent (event); float x = 0, y = 0;/ /Get the number of touch points final int pointercount = Event.getpointercount ();//Get multiple touch points for X and y mean 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, IsCan Drag = False;mlastx = X;mlasty = y;} Lastpointercount = Pointercount;switch (Event.getaction ()) {case MOTIONEVENT.ACTION_MOVE:LOG.E (TAG, "ACTION_MOVE"); float dx = x-mlastx;float dy = y-mlasty;if (!iscandrag) {Iscandrag = Iscandrag (dx, dy);} if (Iscandrag) {RECTF RECTF = GETMATRIXRECTF (); if (getdrawable ()! = null) {Ischeckleftandright = Ischecktopandbottom = True ;//If the width is less than the screen width, move left and right 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;}

First we get the number of touch points, and then find the average of multiple touch points, set to our Mlastx, mlasty, and then when moving, get dx, dy for range check, Call Mscalematrix.posttranslate to set the offset, of course, after the completion of the setup, you need to check again, you can not move the picture with the screen edge white edge, after the completion of verification, call Setimagematrix.

Here: We need to note that we do not have a replication action_dowm because, Action_down in the case of multi-touch, as long as there is a finger pressed state, the other finger press will not trigger Action_down again, but after more than one finger, The average of the touch points can change a lot, so we don't use Action_down. Whenever the number of touch points changes, we will follow the new current mlastx,mlasty.

Here are the two private methods used above, one for checking the bounds, and one for determining whether a drag is being done:

/** * 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;}

In this way, we can be happy to zoom in, zoom out and move it ~ ~ ~

: This time for a man's picture, one of the protagonists of our escape, tbug~


Our zoom + Mobile Fix ~ ~

2. Double-click Zoom in and Zoom out

When it comes to double-click events, our Gesturedetector is finally on the scene, this dude can capture double-click events ~ ~

1, the use of Gesturedetector

Because Gesturedetector sets the listener, the method is a large string, and we just need to ondoubletap this callback, so we're going to use one of its inner class Simpleongesturelistener, which implements the empty implementation of the other methods of the interface.

But there are a few more questions that need to be discussed before we can start our code:

1. How do we change the size of the double click?

I am like this, according to the current zoom value, if it is less than 2, we double-click directly to become the original image of twice times, if it is between the 2,4, we double-click directly for the original image 4 times times, the other state is 4 times times, double-click to revert to the original size.

If you think this is inappropriate, you can adjust according to your hobby.

2, we double-click Change, need an animation ~ ~ such as our example of the demonstration, the picture is large, full-screen display when the initscale=0.5 left, if the double-click to 2, that is, an instant four times times larger, without a transition effect, to the user's feelings will be particularly poor. So, we are going to use Postdelay to perform a runnable,runnable that is again based on the scale value of the of course.

First, in the construction method, we complete the initialization of the Gesturedetector, and set the ONDOUBLETAP monitoring

Public Zoomimageview (context context, AttributeSet Attrs) {Super (context, attrs); mscalegesturedetector = new Scalegesturedetector (context, this); 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 Auto Scalerunnable (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;}}); Mtouchslop = Viewconfiguration.get (context). Getscaledtouchslop (); Super.setscaletype (Scaletype.matrix); This.setontouchlistener (this);}

1, when double-click, the first to determine whether the automatic scaling, if in, direct retrun;

2, then entered our if, if the scale is of course less than 2, then through the view. Send a runnable for execution; other similar;

Here's a look at our runnable code:

/** * 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 target scaling {final float Deltascale = Mtargetscale/currentscale;mscalematrix.postscale (Deltascale, DELTASCAle, x, y); Checkborderandcenterwhenscale (); Setimagematrix (Mscalematrix); isautoscale = false;}}} 

When the code is finished, we still need to pass on our event to it, still in the Ontouch method:

@Overridepublic boolean OnTouch (View V, motionevent event) {if (Mgesturedetector.ontouchevent (event)) return true;

OK, double click to zoom in and zoom out of the function is done, the following test ~ ~ ~

, can finally use the simulator ~ ~:



3. Dealing with conflicts with Viewpager

Directly take our picture as Viewpager item, imagine, there must be conflict ~ ~

1. layout file

<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>

2. Activity Code

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;}});}}

Now run directly, found Viewpager good, but our picture enlarged, moving and Viewpager conflict, and can not move the ~ ... Wipe the rub ...

3. Dealing with conflicts

Now we think quickly, remember to learn the event distribution mechanism, our zoomimageview in Viewpager, if we do not want to be intercepted, then how to do?
The first thing you don't want to be intercepted is that our width or height is greater than the width or height of the screen, because we can move at this point and we don't want to be intercepted. Next, don't want to be intercepted:

GetParent (). Requestdisallowintercepttouchevent (True);

A line of code is sufficient, if you are in the event distribution, not to be intercepted unclear, you can refer to: How not to be intercepted.

Put together our code is:

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);}

~ When the width or height is greater than the screen width or height, the drag effect is thought to be moving the picture, and vice versa let Viewpager to handle

The effect at this point:


OK, now has been resolved and Viewpager conflict, PS: not should double-click can also enlarge two times to 4 times times,,,, good nausea ...

4, the arrival of the border incident to Viewpager processing

Some users may also want to be able to give the event to Viewpager when the picture reaches the boundary and can no longer be dragged.

It is in the action_move, judging that the current has reached the border, and still in the pull, the event is given to Viewpager

if (Iscandrag) {if (getdrawable () = null) {if (GETMATRIXRECTF (). left = = 0 && dx > 0) {getParent (). Requestdisallo Wintercepttouchevent (false);} if (GETMATRIXRECTF (). Right = = getwidth () && DX < 0) {getParent (). Requestdisallowintercepttouchevent (false);}

The effect at this point:


OK, actually added this after, experience general ha ~ ~ ~



Finally finished, there may be bugs in the code, found the problem, or solve the found bug, I hope you can directly under the blog message, but also to facilitate others ~ ~

Here, our Android gesture detection is built to support the zoom pan of the picture preview effect end ~~!


It is recommended to enlarge the double-click to 4 times times, commenting out an IF


Continuous double-click to enlarge, feel uncomfortable, the code has been uploaded, I will not retransmit, if you also feel uncomfortable, you can comment on your own.


Single-chart source click to download


Viewpager version Source download




-------------------------------------------------------------------------------------------------------

Finally post an ad:

First recorded video ~ ~ ~ also hope that everyone support, common progress ~

High Imitation 5.2.1 main interface and message alert












Android gesture detection to create a picture preview that supports zoom panning (bottom)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.