Android TouchEvent's Requestdisallowintercepttouchevent

Source: Internet
Author: User
Tags new set

1 unfold from one detail

The previous days collection of @ Zheng Haibo-mobctrl swiperefreshlayout, want to study how to achieve. When the implementation of their own to find a problem: in the ListView distance above a certain distance to start the pull down, to resist the above content after the slide, while the swiperefreshlayout can continue to pull down, and trigger the drop-down refresh. :

The left image starts to slide and the right pull to the top cannot continue pulling down

After some troubleshooting, found that my own implementation of the code, in the Onintercepttouchevent can receive 1 Action_down, and 2 action_move, and then no longer accept action_move events, Causes the child view to be unable to update whether it can drop down, whether it is in a drop-down state, and Swiperefreshlayout can receive successive Action_move events.

Finally found that incredibly is swiperefreshlayout in a humble function rewrite implementation, the code is as follows:

@OverridepublicvoidrequestDisallowInterceptTouchEvent(boolean b) {    // Nope.}

Swiperefreshlayout inherited from Viewgroup,requestdisallowintercepttouchevent is covered by the following code in ViewGroup:

 Public void requestdisallowintercepttouchevent(BooleanDisallowintercept) {if(Disallowintercept = = ((Mgroupflags & flag_disallow_intercept)! =0)) {//We ' re already in the assume our ancestors is too        return; }if(disallowintercept)    {mgroupflags |= flag_disallow_intercept; }Else{mgroupflags &= ~flag_disallow_intercept; }//Pass It up to our Parent    if(Mparent! =NULL) {mparent.requestdisallowintercepttouchevent (disallowintercept); }}

Why a simple rewrite, can solve this problem?

2 Android TouchEvent

The touch event is received through the underlying, passed to the Viewrootimpl, distributed to the Phonewindow Decorview, first callback to the activity's dispatchtouchevent processing, Then go back to Decorview and start dispatch to the child view, and the delivery logic in a viewgroup is as follows:

TouchEvent dispatchtouchevent Process

When TouchEvent dispatchtouchevent into a viewgroup, there is a three-step judgment, as shown in light green.

    • Disallowintercept?
      the role of Disallowintercept
      The ViewGroup has a disallowintercept switch that lets you set whether this ViewGroup masks onintercepttouchevent events. If this switch is turned on, this viewgroup skips its own onintercepttouchevent event and dispatchtouchevent directly to the child view.
      Reset disallowintercept
      Disallowintercept, the Action_down is reset every time, and the default is to allow Onintercepttouchevent to be called.
//viewgroup.dispatchtouchevent@Override Public Boolean dispatchtouchevent(Motionevent ev) {    ...Booleanhandled =false;if(Onfiltertoucheventforsecurity (EV)) {Final intAction = Ev.getaction ();Final intactionmasked = action & motionevent.action_mask;//Handle an initial down.        if(actionmasked = = Motionevent.action_down) {//Throw away all previous state when starting a new touch gesture.            //The framework may has dropped the up or cancel event for the previous gesture            //Due to a app switch, ANR, or some other state change.Cancelandcleartouchtargets (EV);        Resettouchstate ();    }        ...    } ...}/** * * Resets all touch state in preparation for a new cycle. *///viewgroup.resettouchstatePrivate void resettouchstate() {cleartouchtargets (); Resetcancelnextupflag ( This);    Mgroupflags &= ~flag_disallow_intercept; Mnestedscrollaxes = Scroll_axis_none;}

Each time the user presses the swipe to lift the action for a complete set of actions. A new set of actions starts, that is, when the user starts tapping the screen, ViewGroup resets the current disallowintercept switch and reverts to allowing the onintercepttouchevent state to be called.

    • Intercept?
      onintercepttouchevent return value is True
      When the ViewGroup onintercepttouchevent is called, the return value is true, indicating that the current ViewGroup intercepts the TouchEvent event, and this ViewGroup ontouchevent receives a callback;
      Onintercepttouchevent return value is False
      If the return value is False, call Dispatchtransformedtouchevent to find the child view hit on this point, and if you find a child view, call the Dispatchtouchevent event of the child view, Otherwise, call Super.dispatchtouchevent, which calls the dispatchtouchevent implementation of view, where the Ontouchevent function is called to handle this touchevent event.
      onintercepttouchevent Summary
      The onintercepttouchevent process is the parent viewgroup-> child viewgroup-> Sun Viewgruop, if one of the ViewGroup intercepts the event, then this viewgroup, This viewgroup directly handles the Ontouchevent event, and TouchEvent is not dispatch down, but begins to return.

    • Handled?
      ontouchevent return value is True
      If the return value is true, the touchevent is processed
      Ontouchevent return value is False
      If False, return to the parent ViewGroup, and the parent ViewGroup will continue to hand over to this viewgroup sibling view processing.

3 requestdisallowintercepttouchevent

Child View calls Requestdisallowintercepttouchevent (true) after the action_down of Onintercepttouchevent. Then all parent viewgroup of this child view will skip the onintercepttouchevent callback, which is what happens at the beginning of the article: After Action_move starts, the latter Action_move events of the parent ViewGroup are not received. Then it can be concluded that ScrollView, ListView, and other sub-view after the judge began to swipe and intercept the event, called Requestdisallowintercepttouchevent (True), Causes all parent ViewGroup to skip the onintercepttouchevent callback, directly dispatchtransformedtouchevent to the ScrollView or ListView, implementing the Code as follows:

 @Override Public Boolean onintercepttouchevent(Motionevent ev) {    ...Switch(Action & Motionevent.action_mask) { CaseMotionevent.action_move: {...Final intYdiff = Math.Abs (y-mlastmotiony);if(Ydiff > Mtouchslop && (getnestedscrollaxes () & scroll_axis_vertical) = =0) {misbeingdragged =true;                Mlastmotiony = y;                Initvelocitytrackerifnotexists ();                Mvelocitytracker.addmovement (EV); Mnestedyoffset =0;if(Mscrollstrictspan = =NULL) {Mscrollstrictspan = Strictmode.entercriticalspan ("Scrollview-scroll"); }FinalViewparent parent = GetParent ();if(Parent! =NULL) {Parent.requestdisallowintercepttouchevent (true); }            } Break;    ...        } }returnmisbeingdragged;}

If the slide exceeds the mtouchslop threshold, it is determined that scrollview is sliding, so the onintercepttouchevent callback of the parent ViewGroup is started to be masked. So if requestdisallowintercepttouchevent is covered in the parent viewgroup of this scrollview, and nothing is done, Then ScrollView can not block out the parent ViewGroup Onintercepttouchevent callback, then ScrollView began to handle the sliding action_move will also be received by the parent ViewGroup, It also solves the problem.

4 applications

This problem also exists in Chrisbanes's Android-pulltorefresh project, which can only be repaired in the following 2 steps:
1. Create a new Refreshableviewwrapperlayout.java

 PackageCom.handmark.pulltorefresh.library;ImportAndroid.annotation.TargetApi;ImportAndroid.content.Context;ImportAndroid.os.Build;ImportAndroid.util.AttributeSet;ImportAndroid.widget.FrameLayout;/** * Created by Asha on 15-8-28. * Asha [email protected] */ Public  class refreshableviewwrapperlayout extends framelayout {     Public Refreshableviewwrapperlayout(Context context) {Super(context); } Public Refreshableviewwrapperlayout(context context, AttributeSet attrs) {Super(context, attrs); } Public Refreshableviewwrapperlayout(context context, AttributeSet attrs,intDEFSTYLEATTR) {Super(Context, attrs, defstyleattr); }@TargetApi(Build.version_codes. LOLLIPOP) Public Refreshableviewwrapperlayout(context context, AttributeSet attrs,intDefstyleattr,intDefstyleres) {Super(Context, Attrs, defstyleattr, defstyleres); }@Override     Public void requestdisallowintercepttouchevent(BooleanDisallowintercept) {//do Nothing}}
    1. Implementation of Addrefreshableview in replacement pulltorefreshbase
privatevoidaddRefreshableView(Context context, T refreshableView) {        //mRefreshableViewWrapper = new FrameLayout(context);        //替换为        new RefreshableViewWrapperLayout(context);        mRefreshableViewWrapper.addView(refreshableView, ViewGroup.LayoutParams.MATCH_PARENT,            ViewGroup.LayoutParams.MATCH_PARENT);        new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,            LayoutParams.MATCH_PARENT));}
5 Annotations of the image

The startscrollifneeded function is called after the action_move of Abslistview is started, and there is a comment in the function:

Time to start stealing events! Once we ' ve stolen them, don ' t let anyone steal from us

hahaha, my events, no one will ever steal from me!

6 additional small details in the Swiperefreshlayout implementation
    • To determine if the child can also slide upwards
      If you can swipe, let the child view handle slide
ViewCompat.canScrollVertically(child,-1);
    • Standard sliding Start threshold value
final ViewConfiguration configuration = ViewConfiguration.get(mContext);mTouchSlop = configuration.getScaledTouchSlop();
    • Synchronous displacement Method of view
      Compared to asynchronous Requestlayout, this method is executed synchronously.
child.offsetTopAndBottom(offset);
7 questions

Why are the ListView and ScrollView masking these events so that the parent ViewGroup callback onintercepttouchevent? For efficiency reasons or simplifying logic to avoid slipping errors, expect expert answers.

8 Reference

Swiperefreshlayout Source Code
Android SDK 22 Source code
Explore the causes of requestdisallowintercepttouchevent failure

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

Android TouchEvent's Requestdisallowintercepttouchevent

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.