Distribution, interception, and execution of Android events

Source: Internet
Author: User

In normal development, we often encounter events such as clicks and swipes. Sometimes there are a variety of sliding conflicts between different view. For example, if both the inside and outside of the layout can slide, then there will be a conflict. This time we need to understand the Android event distribution mechanism.


The Android Touch event distribution process is done together in three important ways: Dispatchtouchevent, Onintercepttouchevent, Ontouchevent. Let me introduce these three methods in general.

    • public boolean dispatchtouchevent (motionevent ev)

Used for the distribution of events. If the event can be passed to the current view, then this method must be called, and the result will be affected by the Dispatchtouchevent method of the ontouchevent and downlevel view of the current view, indicating whether the current event is consumed. Action_down dispatchtouchevent () returns True, subsequent events (Action_move, action_up) are passed again if False,dispatchtouchevent () is returned Can not receive the ACTION_UP, Action_move. Simply put, it is when Dispatchtouchevent is doing event distribution that only the previous action returns true to trigger the latter action.

    • public boolean onintercepttouchevent (Motionevent event)

This method is called in the Dispatchtouchevent method and is used to intercept an event. If the current view intercepts an event, the method is not called again in the same sequence of events, and the returned result indicates whether to intercept the current event. It is the method provided by ViewGroup and returns false by default.

    • public boolean ontouchevent (Motionevent event)

Called in the Dispatchtouchevent method to handle the Click event, the return result indicates whether the current event is consumed (true indicates consumption, false means no consumption), and if not consumed, the current view cannot receive the event again in the same sequence of events. Both view and ViewGroup have this method, and the view defaults back to true, indicating that the event was consumed.

In view, there are two callback functions:

publicbooleandispatchTouchEvent(MotionEvent ev);    publicbooleanonTouchEvent(MotionEvent ev);

In ViewGroup, there are three callback functions:

publicbooleandispatchTouchEvent(MotionEvent ev);    publicbooleanonInterceptTouchEvent(MotionEvent ev);    publicbooleanonTouchEvent(MotionEvent ev);

What are the differences and relationships between the three methods mentioned above? This is represented by a pseudo-code:

publicbooleandispatchTouchEvent(MotionEvent ev) {      booleanfalse;      if(onInterceptTouchEvent(ev)){          consume = onTouchEvent(ev);      else {          consume = child.dispatchTouchEvent(ev);      }      return consume;  }  

Through the pseudocode above, you may have a clearer idea of the delivery rules for click events: for a root viewgroup, when a click event is generated, it is first passed to it, and then its dispatchtouchevent is called. If the ViewGroup Onintercepttouchevent method returns True to indicate that it wants to intercept this event, then the event will be handed to the ViewGroup handler, whose Ontouchevent method will be called If the ViewGroup Onintercepttouchevent method returns false, it means that it does not intercept this event, which is the child element that the current event continues to pass to it, and then the Dispatchtouchevent method of the child element is called. So repeatedly until the event is finally processed.

The following images are referenced from [EoE]:

    • Figure one: Action_down is not consumed

    • Figure II (i): Action_down was consumed by the view

    • Figure II (II): Subsequent action_move and up will look for the view without being intercepted

    • Figure three: The follow-up was intercepted

    • Figure four: Action_down was intercepted from the start

View event distribution Source code Analysis Dispatchtouchevent method
publicdispatchTouchEventevent) {      ifnull && (mViewFlags & ENABLED_MASK) == ENABLED && mOnTouchListener.onTouch(thisevent)) {          returntrue;      }      return onTouchEvent(event);  

If montouchlistener! = null, (mviewflags&enabled_mask) ==enabled and Montouchlistener.ontouch (this, event) all three conditions are true, Returns True if the Ontouchevent (event) method is executed and returned.

To summarize, the Ontouch can be executed with two prerequisites (all satisfied):

 1.设置了OnTouchListener 2.控件是enable状态

And ontouchevent can be executed to meet any one of the following three conditions:

 1.没有设置OnTouchListener 2.控件不是enable状态 3.onTouch返回false

Take a look at the return value of Dispatchtouchevent, which is actually controlled by the return value of the Ontouch and ontouchevent functions, which means that the touch event is successfully consumed and returns True, which also returns true, indicating that the distribution was successful, The subsequent sequence of events is also distributed here, and if false, the distribution fails and the sequence of events thereafter is no longer distributed.

Ontouchevent method
if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {       ...       return true; }

The ontouchevent of view consumes the event by default (this method returns True) unless it is not clickable (clickable and longclickable are also false). And the view's longclickable default is the false,clickable attribute to divide the situation, for example button default is True,textview, ImageView defaults to False.

publicbooleanperformClick() {      sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);      ifnull) {          playSoundEffect(SoundEffectConstants.CLICK);          mOnClickListener.onClick(this);          returntrue;      }      returnfalse;  

This is not the onclicklistener we are familiar with, it was originally called in the Ontouchevent. As long as Monclicklistener is not NULL, it will call its OnClick method.
Summing down the onclick can be performed with two prerequisites (all satisfied):

 1.可以执行到onTouchEvent 2.设置了OnClickListener

The event forwarding process for the entire view is:

Finally, there is a question, can setonlongclicklistener and Setonclicklistener only execute one?
A: No, as long as the onclick in the Setonlongclicklistener returns false, all two will be executed; returning true will mask Setonclicklistener.

ViewGroup Event Distribution Source Analysis Dispatchtouchevent method
...if(Disallowintercept | |!onintercepttouchevent (EV)) {ev.setaction (Motionevent.action_down);Final intScrolledxint = (int) Scrolledxfloat;Final intScrolledyint = (int) Scrolledyfloat;FinalView[] children = Mchildren;Final intCount = Mchildrencount; for(inti = count-1; I >=0; i--) {FinalView child = Children[i];if((Child.mviewflags & visibility_mask) = = VISIBLE | | child.getanimation ()! =NULL) {Child.gethitrect (frame);if(Frame.contains (Scrolledxint, Scrolledyint)) {Final floatXC = Scrolledxfloat-child.mleft;Final floatYC = Scrolledyfloat-child.mtop;                             Ev.setlocation (XC, YC); Child.mprivateflags &= ~cancel_next_up_event;if(Child.dispatchtouchevent (EV)) {//Event handled, we have a target now. Mmotiontarget = child;return true; }                         }                     }                 }             }

Both may enter the if code snippet (that is, the event is distributed to the child view):

1、当前不允许拦截,即disallowIntercept = true.2、当前没有拦截,即onInterceptTouchEvent(ev)返回false.

Note: Disallowintercept is the ability to disable event interception, which is false by default and can be set by Viewgroup.requestdisallowintercepttouchevent (Boolean) and onintercepttouchevent (EV) can make a carbon copy.

After entering the if code snippet, through a For loop, traverse all sub-views under the current ViewGroup to determine whether the currently traversed view is a clicked view, and if so, call the view's dispatchtouchevent, has entered the view of the event distribution process, the above is said. When child.dispatchtouchevent (EV) returns True, it is mmotiontarget=child, and then return True, Indicates that the Dispatchtouchevent return value of ViewGroup is affected by the Dispatchtouchevent return value of Childview, the Child view event distribution succeeds, and the ViewGroup event distribution succeeds. The subsequent sequence of events is also distributed here (from above: the clickable or longclickable of the child view can be successfully distributed), and if the ViewGroup event distribution fails or the child view is not found (click on an empty location), Will go to its ontouchevent, the subsequent sequence of events will not be distributed, go straight to ontouchevent.

The event forwarding process for the entire viewgroup is:
Dispatchevent->onintercepttouchevent->child.dispatchevent-> (setontouchlistener->ontouchevent)

The above summary is based on: if not intercepted, then how to intercept it?

publicbooleanonInterceptTouchEvent(MotionEvent ev) {      returnfalse;  

The code is very simple, only one sentence, that is, return False,viewgroup by default is not intercepted. If you need to intercept, just return to true, so that the event will not be passed to the child view, and if you return true, the Down,move,up child view will not capture the event; If you return true in MOVE, The child view does not capture events on move and up.

How to not be intercepted:
If the ViewGroup onintercepttouchevent (EV) return True when Action_move, that is, the move and the up event of the child view are intercepted, and what happens when the child view wants to still respond to move and up?
A: Onintercepttouchevent is defined in the ViewGroup, and the child view cannot be modified. Android gives us a way: Requestdisallowintercepttouchevent (Boolean) is used to set whether or not to allow interception, which we write directly in the dispatchtouchevent of the Child view:

@Override PublicBooleandispatchtouchevent(motioneventEvent) {getParent (). Requestdisallowintercepttouchevent (true);intAction =Event. Getaction ();Switch(action) { CaseMOTIONEVENT.ACTION_DOWN:LOG.E (TAG,"Dispatchtouchevent Action_down"); Break; CaseMOTIONEVENT.ACTION_MOVE:LOG.E (TAG,"Dispatchtouchevent action_move"); Break; CaseMOTIONEVENT.ACTION_UP:LOG.E (TAG,"Dispatchtouchevent action_up"); Break;default: Break; }returnSuper.dispatchtouchevent (Event); }

GetParent (). Requestdisallowintercepttouchevent (True); This allows the child view to capture the move and the up event even if the ViewGroup return true at the time of the move.
Note: If ViewGroup in the onintercepttouchevent (EV) Action_down directly return true, then the child view is no way to capture the event!


About the code process has been summarized above ~
1, if ViewGroup found to be able to handle the event of the view, then directly to the child view processing, their own ontouchevent will not be triggered;
2, can through the carbon onintercepttouchevent (EV) method, intercept the child view of the event (that is, return true), the event to their own processing, will execute their own corresponding Ontouchevent method
3. Child view can be called by GetParent (). Requestdisallowintercepttouchevent (True); Prevents ViewGroup from intercepting its move or up event;
OK, so what are the problems that can be solved in practical application?
For example, you nested a edittext in the ScrollView, when the edittext in the text content too much out of range, you want to slide up and down so that the edittext text scroll out, but found that the scroll is ScrollView. At this point we set the EditText Ontouch event, set the Ontouch to not allow the scrollview to intercept my events, and finally change the state back when up.

@Override Public Boolean OnTouch(View view, Motionevent motionevent) {if((view.getid () = = R.id.tousucontentedittext && canverticalscroll (tousucontentedittext))) {view.getparent (). Requestdisallowintercepttouchevent (true);if(motionevent.getaction () = = motionevent.action_up) {view.getparent (). Requestdisallowintercepttouchevent (false); }        }return false; }Private Boolean Canverticalscroll(EditText EditText) {intscrolly = edittext.getscrolly ();intScrollrange = Edittext.getlayout (). GetHeight ();intScrollextent = Edittext.getheight ()-Edittext.getcompoundpaddingtop ()-Edittext.getcompoundpaddingbottom ();intScrolldifference = scrollrange-scrollextent;if(Scrolldifference = =0) {return false; }return(Scrolly >0) || (Scrolly < Scrolldifference-1); }

Distribution, interception, and execution of Android events

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.