Simple and flexible solution to the problem of gesture conflict caused by viewgroup nesting

Source: Internet
Author: User

Reprint please indicate the original address: simple and flexible to solve the problem of gesture conflict caused by viewgroup nesting

This is followed by an Android drop-down refresh pull-up loading a variety of application scenarios Super Big Broadcast (on), here is how to easily and flexibly solve the viewgroup nested gesture conflict problem. Although this is only a case of Viewpager, it provides a general idea for solving such problems.

First look at the NetEase news Client interface effect:

  • When the direction of the gesture is the direction of the Blue Arrow area, sliding in response to a ListView
  • when the gesture when the direction is the yellow arrow area direction, picture slide in response to Viewpager

Previous implementation of the demo, gesture effect response and the same


There are two main types of gesture conflicts that arise with viewgroup nesting:

    1. When a gesture action is applied to a child view, we want to be able to respond to the corresponding event of the parent ViewGroup
    2. When a gesture action is applied to a child view, we want to be able to respond to the corresponding event of the child view

For 11 simple and crude solutions: in the Onintercepttouchevent method of the parent viewgroup, the child view is intercepted directly
For a 2 or a simple rough solution: In the Dispatchtouchevent method of the child view, tell the parent ViewGroup by Requestdisallowintercepttouchevent (true), do not intercept me.
The gesture interaction of the above scheme is sometimes not so friendly and natural, in the actual situation of the project, it is more complicated. For example, in the ListView nested picture Carousel Viewpager, when the gesture in the horizontal direction <45°, the response to the Viewpager picture carousel, in the vertical direction of the <45°, in response to the slide of the ListView. Of course, you can also set the minimum distance to move a set in the X direction and in the Y direction according to the gesture, and then respond to different events.

Here is a general scenario for solving the above problems:

    1. gesture action in child view, whether you want to respond to the parent viewgroup, or the response child view, are given to the child view processing;
    2. In the Dispatchtouchevent method of child view, Pass the Motionevent event to the listener Ongesturelistener
    3. Based on the listener's no gesture result, decide whether to respond to the parent ViewGroup event, or to respond to the child view event
First write a small test demo, define a sub view
public class SubView1 extends View {private static String TAG = SubView1.class.getSimpleName ();p rivate gesturedetector mGe Sturedetector;private Paint paint = new paint ();p ublic SubView1 (context context) {super (context);} Public SubView1 (context context, AttributeSet Attrs) {Super (context, attrs);//Set Listener Mgesturedetector for Mgesturedetector = new Gesturedetector (context, new Mtouchdetector ()),//guaranteed to trigger the corresponding event setfocusable (true); Setclickable (true); SetEnabled ( true); Setlongclickable (true);} protected void onmeasure (int widthmeasurespec, int heightmeasurespec) {//Specify width and height setmeasureddimension (600, 200);// Super.onmeasure (Widthmeasurespec, heightmeasurespec);} @Overridepublic void OnDraw (canvas canvas) {//TODO auto-generated method Stubsuper.ondraw (Canvas);p aint.settypeface ( Typeface.defaultfromstyle (Typeface.bold)) Canvas.drawcolor ((Color.parsecolor ("#FFA07A")); Canvas.drawtext (" SubView1 ",", "," N "," paint "); @Overridepublic boolean dispatchtouchevent (Motionevent event) {int action = event.getaction (); SWITCH (Action) {case motionevent.action_down://l.i (TAG, "dispatchtouchevent action_down"); break;case motionevent.action_move://l.i (Tag, "Dispatchtouchevent action_move"); break;case motionevent.action_up://L.i (Tag, " Dispatchtouchevent action_up "); break;default:break;} GetParent (). Requestdisallowintercepttouchevent (True); First tell the Father ViewGroup, do not intercept me my mgesturedetector.ontouchevent (event); Pass the Motionevent event to the Listener Ongesturelistenerreturn super.dispatchtouchevent (event) via Gesturedetector;} Class Mtouchdetector extends Simpleongesturelistener {//Touch down triggers public boolean ondown (Motionevent e) {l.i (TAG, "OnD Own "); return Super.ondown (e);} public boolean onscroll (motionevent E1, motionevent e2,float Distancex, float distancey) {//tan (60°), gesture with vertical direction greater than 30 °, Onscroll of the corresponding child view, onscroll of the parent ViewGroup will not respond if (1.732*math.abs (Distancex) >= Math.Abs (Distancey)) {l.i (TAG, "Do not intercept Me") ); GetParent (). Requestdisallowintercepttouchevent (true);//Tell the Father ViewGroup not to intercept me, the event I handle return true;} else {getParent (). RequestdisallowintercepttoUchevent (false);//Tell the parent viewgroup to intercept me, in response to the parent ViewGroup's onscrolll.i (TAG, "intercept Me"); return false;} public boolean onfling (Motionevent E1, motionevent E2, float velocityx,float velocityy) {l.i (TAG, "onfling"); return super . onfling (E1, E2, Velocityx, Velocityy);} Double-click the second touch down when trigger public boolean Ondoubletap (Motionevent e) {l.i (TAG, "Ondoubletap"); return Super.ondoubletap (e);} public boolean ondoubletapevent (Motionevent e) {l.i (TAG, "ondoubletapevent"); return Super.ondoubletapevent (E);}}}
Redefine parent ViewGroup
public class Mlinearlayout extends LinearLayout {private static String TAG = MLinearLayout.class.getSimpleName ();//Priva Te static String TAG = SubView1.class.getSimpleName ();p rivate gesturedetector mgesturedetector; @SuppressLint (" Clickableviewaccessibility ") Public mlinearlayout (context context, AttributeSet Attrs) {Super (context, attrs); Mgesturedetector = new Gesturedetector (context, new Mtouchdetector ()); This.setontouchlistener (new Ontouchlistener () { @Overridepublic boolean OnTouch (View V, motionevent event) {return mgesturedetector.ontouchevent (event);}); Setfocusable (True); Setclickable (true); setenabled (true); Setlongclickable (true);} @SuppressLint ("Newapi") public mlinearlayout (context context, AttributeSet attrs, int defstyle) {Super (context, attrs, Defstyle);} Public Mlinearlayout (Context context) {super (context);} Class Mtouchdetector extends Simpleongesturelistener {public boolean onscroll (motionevent E1, Motionevent e2,float Distancex, float Distancey) {l.i (TAG, "onscroll"); returntrue;}} @Overridepublic boolean onintercepttouchevent (Motionevent event) {//TODO auto-generated method stub Mgesturedetector.ontouchevent (event); return false;}} <span style= "FONT-SIZE:11.9999990463257PX; Font-family:arial, Helvetica, Sans-serif; Background-color:rgb (254, 254, 254); " >      </span>
outside is mlinearlayout, inside is SubView1
when the SubView1 is sliding, the gesture >30° with the vertical direction (level), it tells the parent ViewGroup not to intercept me, the event I handle, the onscroll of the parent ViewGroup will not execute. When the SubView1 is sliding, the gesture is <30° with the vertical direction (relatively upright), it tells the parent viewgroup to intercept me, and the parent ViewGroup onscroll execution.

then solve the problem of the Viewpager of the ListView nested picture Carousel, the idea and the same as above, rewrite Viewpager.
/** * @author wen_er * */public class Myviewpager extends Viewpager {private static String TAG = MyViewPager.class.getSimp Lename ();p rivate gesturedetector mgesturedetector;public Myviewpager (context context) {super (context); Mgesturedetector = new Gesturedetector (context, new Scrolldetector ());} Public Myviewpager (context context, AttributeSet Attrs) {Super (context, attrs);//mgesturedetector = new Gesturedetector (context, New}class Scrolldetector extends Simpleongesturelistener {@Overridepublic boolean onscroll (Motionevent E1, Motionevent e2,float Distancex, float Distancey) {if (Math.Abs (Distancex) >= Math.Abs (Distancey)) {getParent (). Requestdisallowintercepttouchevent (TRUE);//Tell the parent viewgroup not to intercept me return true;} else {getParent (). Requestdisallowintercepttouchevent (false);//Tell parent VIEWGROUPW to intercept me return false;}}} @Overridepublic boolean dispatchtouchevent (Motionevent event) {l.i (TAG, "dispatchtouchevent"); GetParent (). Requestdisallowintercepttouchevent (True); Mgesturedetector.ontouchevent (event);Return Super.dispatchtouchevent (event);}} 

is not very simple, its effect is front, gesture and vertical direction >45°, corresponding Viewpager picture carousel effect, gesture and vertical direction <45°, respond to the sliding of the ListView. Of course, you can change the angle at will, plus a minimum response distance value, to make the gesture interactive effect more natural. The demo source code will be given later.

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Simple and flexible resolution of gesture conflicts caused by viewgroup nesting

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.