Android Sliding components nesting general ideas, multi-tasking gesture ideas, touch transfer ideas, "example" ListView nested Viewpager

Source: Internet
Author: User

In the development of Android UI, we often encounter this requirement:

Two components that support sliding, such as the ListView nested multiple Listview,listview item is a Viewpager or gallary? or ScrollView nested ScrollView and so on.

In general, you may also need to support several features such as:

¤ Two-layer components can slide

¤ Do not let two components slide at the same time, or let two components sliding simultaneously and can adjust themselves

¤ Click events that do not affect the sub view of the underlying view and the child view of the nested view


When we implement these functions, we often encounter some problems:

¤ Click event is blocked

¤view Slide is not smooth (not discussed here)

¤view Sliding condition logic does not conform to design

¤ Does not know how to rewrite the function to satisfy the logic


Here I introduce the general idea of solving this kind of demand, as well as a need case of the ListView and Viewpager which support multi-task gesture.


Touch Transfer ideas:

If you want to put two sliding view nested together, there are a few things you should be aware of:

¤ Like the ListView and Scrollview,viewpager can slide the components, all have their own sliding rules, we had better not to rewrite how to slide them (that is, it is best not to listen to touch the coordinates of the code to slide them). We just have to write the non-sliding business we need, and of course we can't block the execution of the default sliding rule.


¤ ViewGroup, view event distribution delivery mechanism needs to be particularly clear, you know, the ListView inherits from ViewGroup, when a string of touch events occurs, the current activity receives this event, Dispatch to the top layer ViewGroup, the top viewgroup first call dispatchtouchevent, the function inside the Onintercepttouchevent function to determine whether to truncate, if you choose to truncate, Perform your own ontouchevent, the child view will not accept this touchevent, and if not truncated, the viewgroup will be distributed to all of the clicked sub-views (if you do not want to distribute the child view in the clicked Range, You need to rewrite more dispatchevent parts), that is, call the dispatchtouchevent of the child view, as long as there is a return true in the child view (representing the child view consumption of this event), The ViewGroup does not execute this touchevent, and if it does not return true, the ontouchevent () of the viewgroup is called, if it returns false, the event is not consumed, and the onclick is called, If there is still no consumption, then the dispatch function of the ViewGroup returns false.

This set of logic can be complicated, except that the view is not onintercepttouch, so to summarize:

Each view receives an event, if by judgement does not decide to block the event, to determine if there is a sub-view to consume this event, if not, then execute ontouchevent, that is, try to spend, if you do not consume, the view of the dispatch returned false, Indicates that the view includes a branch of the view that does not consume the event.


¤ Need to be very clear about the business needs, because it should be written in the form of code explicitly, but also in the right place (sometimes you may hesitate to perform a multi-task gesture of the parent view, should return a false in the parent view truncation or the dispatch of the child view)

¤ Child View Monopoly Parent view event: This.getparent (). Requestdisallowintercepttouchevent (True); This method prevents the parent view from blocking the event, that is, the event must be accepted. Remember to close this when you finish a set of touches.


Multi-tasking gesture ideas:

It is not very difficult for the reader to design a view multi-tasking gesture (rewrite the ontouchevent, record the coordinates that are pressed, moved, and lifted), but the problem is put on viewq nesting, which you can consider. You may encounter problems such as:

¤ If the child view consumes touchevent, any behavior of the parent view is not invoked.

Solve:

1. If you want parent-child view to consume this event at the same time, you need to rewrite the parent view's dispatch and forcibly call Ontouchevent.

2. If this is the case, you do not want the child view to consume this event, there are two scenarios: rewrite The intercept of the parent view, check the gesture, block the event, rewrite the dispatch of the child view, check the gesture, and return false. One is the parent view Force block, one is the child view mandatory non-consumption.

3. If your current state is not clear which view should be used for this event, you can leave it alone until you decide that you need to block or consume (because your business needs don't have a clear definition of the state, you don't need to define what to do with it).


A simple case, with part of the source code:

Requirements Description:

Each item of a ListView nested Viewpager,listview is defined by an XML layout that includes a viewpager and other parts.

Supported operations:

¤viewpager can slide left and right, the ListView can slide up and down, not at the same time in the sliding, naturally, only the first point to the Viewpager can slide, do not slide the other viewpager.

The ¤listview supports two-finger reduction operations.

¤listview supports ItemClick operation (do not click on a picture in Viewpager).

The images in ¤viewpager support click action.


The first part of the ListView :

Onitemclick defines my own business events, which are triggered when you click on each item and are not consumed by a Viewpager picture view.

In Dispatchtouchevent () determine if the current hand index is greater than or equal to 2, that is, the two-finger operation, forcibly call Ontouchevent, and return, at this time will not call Super.dispatchtouchevent (), That is, the event does not go to the child view.

In Ontouchevent () I was able to simply implement the business requirements of multitasking gestures.

@Overridepublic void Onitemclick (adapterview<?> arg0, View arg1, int arg2, long arg3) {//TODO auto-generated method Stubif (Mset.get (arg2). Size () > 1) this.downgranularity (ARG2);} /** * Custom ListView is used for event distribution processing. * @author Ipip * August 4, 2014 morning 10:46:53 */private class Mylistview extends ListView {public Mylistview (context context) {SUP ER (context); This.setdivider (null);//TODO auto-generated Constructor stub}/** * Handles touch events for ListView */@Overridepublic Boolean ontouchevent (motionevent ev) {switch (Ev.getaction () & Motionevent.action_mask) {case Motionevent.action_ Down:case MotionEvent.ACTION_POINTER_DOWN:if (ev.getpointercount () = = 2) DST = measurefingers (EV); break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_POINTER_UP:if (ev.getpointercount () = = 2 && ndst < DST) { Upgranularity ();d st =-1;} Break;case MotionEvent.ACTION_MOVE:if (Ev.getpointercount () >= 2) {NDST = measurefingers (EV);} break;} if (Ev.getpointercount () >= 2) return True;return super.ontouchevent (EV);} /** * * * @Overridepublic boolean dispatchtouchevent (motionevent ev) {if (Ev.getpointercount () >= 2) {return ontouchevent ( EV);} return super.dispatchtouchevent (EV);}}

Next is ViewpagerThe code:

First explain my ontouchevent (), because my viewpager line can hold 4 pictures (rewrite Getpagewidth () in the adapter), so when the number of pictures is less than 4 o'clock, I do not handle the sliding events, Otherwise there will be a flicker of the image blink (in fact, this is very interesting, it is not clear what the principle).

In dispatch, it is first to determine whether a two-finger operation. The next step is to record the position of the first operation and the judgment of each move.

public class Myviewpager extends Viewpager {public Myviewpager (context context) {super (context);//TODO auto-generated Co Nstructor Stub}public Myviewpager (context context, AttributeSet Attrs) {Super (context, attrs);} Private float xdown;//records the horizontal axis of the finger when pressed. Private float xmove;//records the horizontal axis of the finger when moving. Private float ydown;//records the ordinate when the finger is pressed. Private float ymove;//records the ordinate when the finger moves. Private Boolean viewpagerscrolling = False;private Boolean fatherscrolling = false; @Overridepublic Boolean ontouchevent ( Motionevent ev) {if (This.getchildcount () < 4) return False;return super.ontouchevent (EV);} @Overridepublic boolean dispatchtouchevent (motionevent ev) {//TODO auto-generated method Stubif (Ev.getpointercount () & gt;= 2) Return False;switch (Ev.getaction () & Motionevent.action_mask) {case MotionEvent.ACTION_DOWN:case MotionEvent.ACTION_POINTER_DOWN:xDown = Ev.getrawx (); ydown = Ev.getrawy (); fatherscrolling = False;break;case MotionEvent.ACTION_MOVE:xMove = Ev.getrawx (); ymove = Ev.getrawy (); if (fatherscrolling) {return false;} if (viewpagerscrolling) {return super.dispatchtouchevent (EV);} if (Math.Abs (Ymove-ydown) < && math.abs (Xmove-xdown) > 3) {this.getparent (). Requestdisallowinterceptt Ouchevent (true); viewpagerscrolling = true;} else if (Math.Abs (Ymove-ydown) >=) {fatherscrolling = True;return false;} Elsereturn false;break;case MotionEvent. Action_up:case MotionEvent.ACTION_POINTER_UP:viewPagerScrolling = false;if (ev.getpointercount () = = 1) this.getparent (). Requestdisallowintercepttouchevent (false); break;} return super.dispatchtouchevent (EV);}}

The key sentence above:

if (fatherscrolling) {return false;} if (viewpagerscrolling) {return super.dispatchtouchevent (EV);} if (Math.Abs (Ymove-ydown) < && math.abs (Xmove-xdown) > 3) {this.getparent (). Requestdisallowinterceptt Ouchevent (true); viewpagerscrolling = true;} else if (Math.Abs (Ymove-ydown) >=) {fatherscrolling = True;return false;} Elsereturn false;

If there is a significant lateral movement at that point, and the vertical direction must be within a given number, I determine that I am going to perform a viewpager horizontal slide operation, at which point I assign a value of viewpagerscrolling to True, Then all of the next moves will call Super.dispatchtouchevent () by default, and the block of the parent view will be rejected, applying the default sliding mode until the end of a sequence of events. If the vertical direction moves beyond the range, and the previous lateral movement is not obvious, then I determine the parent view's ListView to slide, when the assignment is fatherscrolling to ture, then each move will return false, that is, all events after consumption.

Of course, after all the fingers were lifted, the states were reset.

After that, each imageview of Viewpager can be simply set to a onclicklistener (), and the parent view and view will not block its click events.

Briefly describe why:
Why is the click of ¤itemclick and ImageView not blocked?

The premise is that grandparents view did not block its events, that is, grandparents view will not consume down-up, will not consume down-move-up. To put it simply, a two-tier view will not consume it as soon as the click is lifted, and it can be passed to the child view in the default way.

¤ Why in the Viewpager to determine whether there is a certain horizontal movement?

If directly let Viewpager consumption of this event, the parent view will not have the opportunity to consume the event, I only with a certain movement as the basis, to determine whether it is vertical or horizontal slip.

You will say I can let the child view consumption, when the vertical direction to move too much to the ListView consumption. In fact, I still want to judge the distance, if the lateral movement of 100px, and then because the vertical movement of 15px will not let viewpager consumption and business needs, since the same to calculate the transverse distance, the best way should be to wait first, When the time is ripe, lock the view that consumes the event until the event chain ends.

¤ Why the ListView in the dispatch to determine whether the double finger instead of the intercept?

Yes, actually all can ...

Here is the screen recording of the new ADT, as if ADT starting from KitKat supports the recording screen:

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.