Android Viewpager + Scalable ImageView

Source: Internet
Author: User
Tags gety

Http://files.cnblogs.com/files/liaolandemengxiang/PhotoWallFallsDemo.rar

http://files.cnblogs.com/files/liaolandemengxiang/ViewPager_imageview%E7%9A%84%E7%BC%A9%E6%94%BE%E4%BC%98%E5% 8c%96%e5%90%8e.rar

The first address is the center scale demo, it is worth noting that the displacement is relative to the (0,0) position of the offset, each time the canvas to redraw the picture

The second is to optimize the future combination of Viewpager and Zoomimageview demo, is through the ImageView callback function also controls whether Viewpager can be scaled. And make changes to the original bug. The main problem with the bug is that there is a calculation error in the center position that is present in the scale of the long picture without considering the height greater than the screen height. There is also the understanding of the maximum zoom factor, the initialization scale is x, but as 1, the maximum zoom factor should be a multiple of x.

Quoted http://www.cnblogs.com/linjzong/p/4212474.html

In the previous Android: hands-on teaching you to build a scalable mobile ImageView Finally, a point of note is raised: When a custom matriximageview such as Viewpager, ListView, etc. with a sliding effect viewgroup, ImageView Custom Drag events conflict with ViewGroup sliding events, and points out that the conflict is due to the fact that ViewGroup intercepts the move event. If you are not familiar with the distribution mechanism of the touch event, you can refer to this android:30 minute to figure out the touch event distribution mechanism.

This article will be based on the Matriximageview, with Viewpager as a test container for further optimization.

Implementation features

    1. When zooming, the gesture does not trigger the Viewpager sliding Toggle item event at the same time.
    2. When a drag operation occurs, the Viewpager slide toggle Item event is not triggered unless the picture has reached the left and right boundary.
    3. When dragging, if the left edge of the picture reaches the left border, you can swipe left to trigger Viewpager to switch to the previous item, and when the right edge of the picture reaches the right border, you can swipe right to trigger Viewpager to switch to the next item.
    4. Only one type of transactional operation (scaling, dragging, or Viewpager toggle item) is performed per down-up (cancel) event period to prevent multiple transactions from interfering with each other.
    5. The transaction is encapsulated into the Matriximageview class, providing a state interface to Viewpager for easy adaptation to a variety of viewgroup.
Implementation principle

When Viewpager is embedded matriximageview, the Matriximgaeview returns true in the Down event, indicating that Viewpager will capture this complete touch event (move-ponit_down-up, etc.) , one of the most important events is the move event, because the Viewpager itself needs to capture the move event in Ontouch to toggle the item operation, and Matriximageview's capture means it will not respond. However, the Viewpager itself controls the release of the touch event, and each touch event is delivered in a recursive hierarchy from top to bottom, before Matriximageview actually gets the move event, The move event must undergo the Viewpager onintercepttouchevent and Dispatchtouchevent events, which perform the interception operation. Viewpager is the move event is filtered in the onintercepttouchevent, and when the moving distance exceeds a certain value, it intercepts the move event and prevents Matriximageview from continuing to handle the touch event. Instead, let the Ontouch event handle itself. So what we have to do is rewrite the Onintercepttouchevent event and decide whether to intercept it by judging the state of Matriximageview.

Specific implementation

Because the container viewpager will intercept the touch event of the child view when it satisfies the condition, you need to customize a viewpager to modify the interception logic. When Matriimageview is scaled and dragged, we don't want Viewpager to intercept. The specific code is as follows:

public class Albumviewpager extends Viewpager implements Onchildmovinglistener {/**  whether the current child control handles drag state  *     / Private Boolean mchildisbeingdragged=false;    @Override Public    Boolean onintercepttouchevent (Motionevent arg0) {        if (mchildisbeingdragged)            return false;        Return super.onintercepttouchevent (arg0);    } @Override public    void StartDrag () {        //TODO auto-generated method stub        mchildisbeingdragged=true;    }    @Override public    void Stopdrag () {        //TODO auto-generated method stub        Mchildisbeingdragged=false ;    }}
Public interface onchildmovinglistener{public        void  StartDrag ();        public void  Stopdrag ();    }

The value of the variable mchildisbeingdragged is determined by determining whether to intercept, while the value of mchildisbeingdragged is set by Matriimageview through the Onchildmovinglistener interface. Don't forget to set up a listening interface for Matriimageview in Pageradapter's Instantiateitem.

    Matriximageview ImageView = (matriximageview) Imagelayout.findviewbyid (r.id.image);    Imageview.setonmovinglistener (Albumviewpager.this);

The transformation of the Viewpager is complete, just add a variable and implement an interface, then the interception of the event is transferred to the Matriximageview.

Then look at the Ontouch method of the reformed Matriximageview.

    /** and Viewpager are correlated, judging whether the current can be left shifted, right shift, or Boolean mleftdragable;          Boolean mrightdragable;        /** whether to move the first time */Boolean mfirstmove=false;        Private PointF Mstartpoint = new PointF ();            @Override public boolean OnTouch (View V, motionevent event) {//TODO auto-generated method stub Switch (event.getactionmasked ()) {case Motionevent.action_down://Set Drag mode MMo                De=mode_drag;                Mstartpoint.set (Event.getx (), event.gety ());                Ismatrixenable ();                Startmove ();                Checkdragable ();            Break                Case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:reSetMatrix ();                Stopmove ();            Break                Case MotionEvent.ACTION_MOVE:if (Mmode = = mode_zoom) {Setzoommatrix (event);                    }else if (Mmode==mode_drag) {Setdragmatrix (event);                }else {stopmove ();            } break;                Case MotionEvent.ACTION_POINTER_DOWN:if (mmode==mode_unable) return true;                Mmode=mode_zoom;                Mstartdis = Distance (event);            Break            Case MotionEvent.ACTION_POINTER_UP:break;            Default:break;        } return Mgesturedetector.ontouchevent (event); }

Where the red part of the code is the modified code, one after the analysis.

/**          *   child controls start moving state, making viewpager unable to intercept touch events for child controls        *        /private void StartDrag () {            if (movelistener!= NULL) Movelistener.startdrag ();        }        /**          *   child control starts to stop moving state, Viewpager will intercept the touch event of the child control        *        /private void Stopdrag () {            if (movelistener!= NULL) Movelistener.stopdrag ();        }

The StartDrag and Stopdrag methods are simple, which is to call the Viewpager pass in the Onchildmovinglistener interface for mchildisbeingdragged settings. When the supervisor hears the down event, it means to start dragging, and when the up and cancel events are received, the end drag is indicated, so that the logic is that ViewGroup will never intercept the touch event, so we also need to set the Stopdrag event elsewhere, as explained later.

The next step is to execute the Checkdragable method in the down event:

        /**          *   based on the current picture left and right edge settings can be dragged state        *        /private void checkdragable () {            mleftdragable=true;            Mrightdragable=true;            Mfirstmove=true;            Float[] Values=new float[9];            Getimagematrix (). GetValues (values);            The left edge of the picture leaves the left border, indicating that the values[matrix.mtrans_x]>=0 Mrightdragable=false is not right-shifted                ;            The right edge of the picture leaves the right border, indicating that it cannot be left            -shifted if ((mimagewidth) *values[matrix.mscale_x]+values[matrix.mtrans_x]<=getwidth ()) {                mleftdragable=false;            }        }

This method resets the state of the three parameters of Mleftdragable, mrightdragable, Mfirstmove. Mleftdragable indicates that the matrix in the current state can be dragged to the left, mrightdragable that the matrix in its current state can be dragged to the right, mfirstmove for each full touch event (from down to up or cancel) The first drag action flag in the. The mleftdragable and mrightdragable are calculated based on the matrix matrices.

Because of the previous functional requirements, it was said that "only one type of transaction operation (scaling, dragging, or Viewpager toggle item) is performed per down-up (cancel) event cycle, so when the scaling operation is performed, the toggle item operation is no longer executed. You can wait until the zoom ends to Stopdrag when you perform the up operation. The move focus is to identify whether to toggle item or drag the picture. View the modified Setdragmatrix code

/** * Set the matrix in drag state * @param event */public void Setdragmatrix (Motionevent event) { if (iszoomchanged ()) {Float dx = event.getx ()-mstartpoint.x;//Get x-axis moving distance float D y = event.gety ()-mstartpoint.y;                        Get the X-axis movement distance//avoid and double-click collisions, more than 10f is considered to be dragged if (math.sqrt (dx*dx+dy*dy) >10f) {                    Mstartpoint.set (Event.getx (), event.gety ());                    Move the Mcurrentmatrix.set (Getimagematrix ()) on the current basis;                    Float[] Values=new float[9];                    Mcurrentmatrix.getvalues (values);                        Dy=checkdybound (Values,dy);                    Dx=checkdxbound (Values,dx,dy);                    Mcurrentmatrix.posttranslate (dx, dy);                Setimagematrix (Mcurrentmatrix);            }}else {Stopdrag (); }}/** * compares the current matrix to verify the DX so that the image moves beyond the imageview boundary * @param valuES * @param DX * @return * * Private float Checkdxbound (float[] values,float dx,float D            Y) {float width=getwidth (); if (!mleftdragable&&dx<0) {//Join and Y-axis contrast, indicates that the item if (Math.Abs (DX) *0.4F&G is not toggled when the vertical gesture is heard. T                Math.Abs (DY) &&mfirstmove) {Stopdrag ();            } return 0; } if (!mrightdragable&&dx>0) {///join and Y-axis contrast, indicating that when the vertical gesture is heard, the item if (Math) is not toggled.                ABS (DX) *0.4f>math.abs (dy) &&mfirstmove) {Stopdrag ();            } return 0;            } mleftdragable=true;            Mrightdragable=true;            if (mfirstmove) Mfirstmove=false;                            if (mimagewidth*values[matrix.mscale_x]<width) {return 0;            } if (values[matrix.mtrans_x]+dx>0) {dx=-values[matrix.mtrans_x];} else if (values[matrix.mtrans_x]+dx<-(mimagewidth*values[matrix.mscale_x]-width)) {dx=-(mIma            Gewidth*values[matrix.mscale_x]-width)-values[matrix.mtrans_x];        } return DX; }

The processing logic is this:

1. Determine if the current zoom level is the original zoom level (iszoomchanged ()), and if not, you can toggle the item directly Stopdrag.

2. If the scaling is done, then determine if the 10f is tired, and when 10f is moved, the movement of the X and Y axes is calculated, and the true movement of the Y axis is calculated by the Checkdybound method.

3. Enter the Checkdxbound method, first determine whether the current can be left to move, if not left and the actual x-axis offset is left, then return x offset of 0, to prevent the left shift. At the same time, if the current is the first move, it means that this is not a left-shift operation, but instead of moving forward the item, then execute the Stopdrag method, so that Viewpager intercept the Matriximageview event distribution. In addition, here and the y-axis offset comparison, is to prevent the implementation of the vertical direction of the slide caused by the Stopdrag,viewpager itself for the x-axis offset/2 is less than the y-axis offset case is not as a toggle item intent, here is set to *0.4 can guarantee that no conflict.

4. Move right.

5. When the first left and right shift results are not toggle item, both mleftdragable and mrightdragable are set to true to indicate that they can move normally. This is the same as the drag processing of a single matriximageview.

This completes the transformation of the Matriimageview embedded inside the viewgroup. The following is a two-point display optimization.

First, a new feature is added to Resetmatrix: When the scaled picture height does not reach the imageview height, the y-axis is centered after up and cancel, preventing the "enlarge picture-y-axis move picture-shrink picture" cause the picture position to be asymmetrical. The exception graph effect is as follows:

/**           *   Reset Matrix *         /        private void Resetmatrix () {            if (checkrest ()) {                Mcurrentmatrix.set ( Mmatrix);                Setimagematrix (Mcurrentmatrix);            } else {                //Determine if y-axis needs correction                float[] values=new float[9];                Getimagematrix (). GetValues (values);                float height=mimageheight*values[matrix.mscale_y];                if (Height<getheight ()) {                    //The Y axis is centered when the picture's true height is less than the height of the container, the y-axis ideal offset is both height difference/2,                    float topmargin= (getheight ()-height )/2;                    if (Topmargin!=values[matrix.mtrans_y]) {                        mcurrentmatrix.set (Getimagematrix ());                        Mcurrentmatrix.posttranslate (0, topmargin-values[matrix.mtrans_y]);                        Setimagematrix (Mcurrentmatrix);}}}        

Optimized scaling X axis symmetry selection problem for scaling operations. When the picture zooms-move x-axis-zooms out, the ImageView center point is scaled to the origin, which may cause the zoomed picture edge to leave the ImageView boundary.

The error graph effect is as follows:

/** * Set Zoom Matrix * @param event */private void Setzoommatrix (Motionevent event) {            The IF (Event.getpointercount () <2) return is only performed when the two points of the screen are simultaneously touched; float Enddis = distance (event);//End Distance if (Enddis > 10f) {//two fingers close together when pixels are greater than ten float scale = enddis/mstartdis;//Gets the zoom multiplier mstartdis=enddis;//resets the distance Mcurrentmatrix.set (Getimagematrix ());                Initialize matrix float[] Values=new float[9];                Mcurrentmatrix.getvalues (values);                Scale = Checkmaxscale (scale, values);                PointF Centerf=getcenter (scale,values);                Mcurrentmatrix.postscale (scale, SCALE,CENTERF.X,CENTERF.Y);                Setimagematrix (Mcurrentmatrix);         }}/** * Gets the center point of the zoom. * @param scale * @param values * @return */private PointF getcenter (float Scale,floa T[] values) {/When the zoom level is less than the original zoom level or is zoomed in, the ImageView center point is returned as the Zoom center point if (scale*values[matrix.mscale_x]<mscale| |            Scale>=1) {return new PointF (GetWidth ()/2,getheight ()/2);            } float Cx=getwidth ()/2;            float cy=getheight ()/2; With ImageView center point as the Zoom center, determine whether the left edge of the zoomed picture will leave the left edge of the ImageView, or if the left edge is the X axis Center if ((GetWidth ()/2-values[matrix.mtrans_x]) *scale&            Lt;getwidth ()/2) cx=0; Determines whether the right edge of the zoom leaves the right edge of the ImageView, or if the right edge is the X-axis Center if ((Mimagewidth*values[matrix.mscale_x]+values[matrix.mtrans_x]) *scal            E<getwidth ()) cx=getwidth ();        return new PointF (CX,CY); }

By judging the width of the image, the decision is to scale the origin with the ImageView midpoint as the x-axis, or to scale the origin with the left and right edges.

So far Matriximageview's functions have been basically perfected, and the specific code is still on my GitHub camera demo. The view if there is a problem can be in this article under the message or private messages I.

Android Viewpager + Scalable ImageView

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.