[Android] View and ViewGroup event distribution mechanism

Source: Internet
Author: User

The problem of sliding collisions (such as scrollview or nesting of Sliddingmenu and ListView) is often encountered in Android development, which requires a deep understanding of the Android Incident response mechanism to solve The incident response mechanism is already an essential knowledge for Android developers.

1. Common methods of Incident response

The user generates a series of events through the Motionevent object during finger-to-screen contact, which has four states:
  

    • Motionevent.action_down: The moment the finger presses the screen (the beginning of all events)

    • Motionevent.action_move: Finger moves on the screen

    • MOTIONEVENT.ACTION_UP: The finger leaves the screen instantly

    • Motionevent.action_cancel: Cancellation gesture, usually generated by the program, will not be generated by the user

      The event onclick, Onlongclick,onscroll, onfling, etc. in Android are made up of a number of touch events (one action_down, n action_move,1 action_up).

      The Android event response mechanism is first distributed (first received by an external view, then to the minimum view of its inner layer), and then processed (from the smallest view cell (event source) to the outer layers. ) is implemented in the form of a.

      Complexity is manifested in the ability to control whether each layer of events continues to be delivered (distributed and intercepted cooperatively), as well as the specific consumption of events (event distribution also has event spending power).

Three important functions involved in 2.android event processing

Event Distribution: Public boolean dispatchtouchevent (motionevent ev)

When a supervisor hears an event, it is first captured by the activity and enters the event distribution process. (Because activity has no event interception, view and ViewGroup) will pass the event to the outermost view's dispatchtouchevent (motionevent ev) method, which distributes the event.
  

    • Return true: Indicates that all events have been digested within the view.

    • Return false: The event is no longer being distributed at this level and is being consumed by the Ontouchevent method of the upper control (if the layer control is already activity, then the event will be consumed or processed by the system).

    • If the event distribution returns the system's default super.dispatchtouchevent (EV), the event is distributed to this layer's event interception onintercepttouchevent method for processing

Event interception: Public boolean onintercepttouchevent (motionevent ev)

    • Return true: Indicates that the event is intercepted and the intercepted event is referred to the ontouchevent of the layer control;

    • Return false: The event is not intercepted and the event is successfully distributed to the child view. and processed by the dispatchtouchevent of the child view.

    • If Super.onintercepttouchevent (EV) is returned, the default is to intercept the event and pass the event to the current view's Ontouchevent method, as with return true.

Event Response: Public boolean ontouchevent (motionevent ev)

return super.dispatchtouchevent (EV) in Dispatchtouchevent (event distribution) and Onintercepttouchevent (event interception returns TRUE or Super.onintercepttouchevent (EV), the event is passed to the Ontouchevent method, which responds to the event.

    • If true, indicates that ontouchevent consumed the event after the event was processed. At this point the event ends;

    • If return Fasle does not respond to an event, then the event will continue to pass to the Ontouchevent method of the upper view until the Ontouchevent method of a view returns True, if the topmost view or false is returned, If the event is not consumed, then in the same event series, the current view cannot receive the event again, and the event is referred to the activity's ontouchevent for processing;

    • If return super.dispatchtouchevent (EV), it means that the event is not responding and the result is the same as return false.

As can be seen from the above process, the event is no longer distributed, whether it returns true or false, and only if it returns super.dispatchtouchevent (EV), indicating that it has the desire to distribute to the lower layer, dispatchtouchevent However, if it is possible to distribute the success, it needs to be audited by the event intercept onintercepttouchevent. Whether the event is passed up is determined by the return value of the ontouchevent.

(Figure from the network)

3.View Source Code Analysis

ImageView, TextView, button, etc. in Android inherit from the view but have not overridden the Dispatchtouchevent method, so the method of the view is used for event distribution.

View Important function part of the source code:

publicdispatchTouchEventevent) {//返回true,表示该View内部消化掉了所有事件。返回false,表示View内部只处理了ACTION_DOWN事件,事件继续传递,向上级View(ViewGroup)传递。    ifnull && (mViewFlags & ENABLED_MASK) == ENABLED &&            mOnTouchListener.onTouch(thisevent)) {  //此处的onTouch方式就是回调的我们注册OnTouchListener时重写的onTouch()方法        returntrue;    }    return onTouchEvent(event);}

The first three conditions are judged:

(1) Check whether the Ontouchlistener () event is set for the button;

(2) Whether the control is enable; (The control is enable by default)

(3) whether the Ontouch () method in the Ontouchlistener monitor implemented in the button returns true;

If the condition is met, the event is consumed and is no longer processed into the ontouchevent. Otherwise, the event will be given to the Ontouchevent method for processing.

public boolean ontouchevent (Motionevent event) {.../* The components of the current Ontouch must be clickable, such as Button,imagebutton and so on, where clickable is true before enteringifmethod, and finally returns true. If it is ImageView, Texitview These default is non-clickable view, here clickable to false, and finally return false. Of course there will be special cases, if the onclick listener is set for these view, clickable will also be true here */if((viewflags & clickable) = = Clickable | | (ViewFlags & long_clickable) = = long_clickable)) {Switch(Event.getaction ()) {Case MOTIONEVENT.ACTION_UP:...                            if(!post (Mperformclick)) {PerformClick ();//actually callback the re-onclick () method in our registered Onclicklistener}...                 Break; Case Motionevent.action_down:...                 Break; Case Motionevent.action_cancel:...                 Break; Case Motionevent.action_move:...                 Break; }returnTrue }returnfalse;}
public boolean performClick() {    ... //    if (li != null && li.mOnClickListener != null) {        ...        li.mOnClickListener.onClick(this);        return true;    }    return false;}
publicvoidsetOnClickListener(OnClickListener l) {    if (!isClickable()) {        setClickable(true);    }    getListenerInfo().mOnClickListener = l;}

The only thing that we rewrite when we register Ontouchlistener
In the OnTouch () method

Returns the False-> execution Ontouchevent method, which causes the onclick () callback method to execute

Returns the True-> Ontouchevent method does not execute, causing the onclick () callback method to not execute

4.ViewGroup Source Code Analysis

The five layout controls, such as LinearLayout in Android, are inherited from ViewGroup, and ViewGroup itself is inherited from view, so the ViewGroup event handling mechanism works for these controls.

  
Part of the source code:

 Public Boolean dispatchtouchevent(Motionevent ev) {Final intAction = Ev.getaction ();Final floatXF = Ev.getx ();Final floatYF = Ev.gety ();Final floatScrolledxfloat = XF + mscrollx;Final floatScrolledyfloat = YF + mscrolly;FinalRect frame = Mtemprect;//This value defaults to False, then we can pass the Requestdisallowintercepttouchevent (Boolean disallowintercept) method       //To change the value of the disallowintercept       BooleanDisallowintercept = (Mgroupflags & flag_disallow_intercept)! =0;//Here is the processing logic of Action_down       if(action = = Motionevent.action_down) {//Clear Mmotiontarget, set Mmotiontarget to null each time Action_down           if(Mmotiontarget! =NULL) {Mmotiontarget =NULL; }//disallowintercept default is False, see ViewGroup's Onintercepttouchevent () method           if(Disallowintercept | |!onintercepttouchevent (EV)) {//1thEv.setaction (Motionevent.action_down);Final intScrolledxint = (int) Scrolledxfloat;Final intScrolledyint = (int) Scrolledyfloat;FinalView[] children = Mchildren;Final intCount = Mchildrencount;//Traverse its child view                for(inti = count-1; I >=0; i--) {//2nd                   FinalView child = Children[i];//If the child view is visible or the child view is performing an animation, it indicates that the view is                   //can accept the touch event                   if((Child.mviewflags & visibility_mask) = = VISIBLE | | child.getanimation ()! =NULL) {//Get the location range of child viewChild.gethitrect (frame);//As touch to the point on the screen above the child view                       if(Frame.contains (Scrolledxint, Scrolledyint)) {//Offset the event to the view ' s coordinate system                           Final floatXC = Scrolledxfloat-child.mleft;Final floatYC = Scrolledyfloat-child.mtop;                             Ev.setlocation (XC, YC); Child.mprivateflags &= ~cancel_next_up_event;//Call the Dispatchtouchevent () method of the child view                           if(Child.dispatchtouchevent (EV)) {//If child.dispatchtouchevent (EV) returns true to indicate                            //The event was consumed, set Mmotiontarget as the child viewMmotiontarget = child;//Direct return True                               return true; }//The event didn ' t get handled, try the next view.                            //Don ' t reset the event ' s location, it 's not                           //necessary here. }                     }                 }             }         }//Judging whether it is action_up or Action_cancel       BooleanIsuporcancel = (Action = = motionevent.action_up) | | (action = = Motionevent.action_cancel);if(Isuporcancel) {//If it is action_up or action_cancel, set the disallowintercept to the default false        //If we call the Requestdisallowintercepttouchevent () method to set Disallowintercept to True        //Reset the Disallowintercept to False when we lift our fingers or cancel the touch event        //So the above disallowintercept defaults to false every time we action_down.Mgroupflags &= ~flag_disallow_intercept; }//The event wasn ' t an Action_down, dispatch it to our target if       //We have one.        FinalView target = Mmotiontarget;//mmotiontarget NULL means that the view of the consumer touch event is not found, so we need to call the ViewGroup parent class's       //dispatchtouchevent () method, which is the Dispatchtouchevent () method of the View       if(target = =NULL) {//We don't have a target, this means we ' re handling the           //event as a regular view. Ev.setlocation (XF, YF);if((Mprivateflags & cancel_next_up_event)! =0) {ev.setaction (motionevent.action_cancel);             Mprivateflags &= ~cancel_next_up_event; }return Super. dispatchtouchevent (EV); }//The code inside this if Action_down will not execute, only action_move       //action_up will come here, if Action_move or action_up intercept.       //touch Event, the Action_cancel is sent to target, and then directly returns True       //Indicates consumption of this touch event       if(!disallowintercept && onintercepttouchevent (EV)) {Final floatXC = Scrolledxfloat-(float) Target.mleft;Final floatYC = Scrolledyfloat-(float) Target.mtop;             Mprivateflags &= ~cancel_next_up_event;             Ev.setaction (Motionevent.action_cancel); Ev.setlocation (XC, YC);if(!target.dispatchtouchevent (EV)) {             }//Clear the targetMmotiontarget =NULL;//Don ' t dispatch this event to our own view, because we already           //Saw it when intercepting, we just want to give the following           //event to the normal ontouchevent ().            return true; }if(Isuporcancel) {Mmotiontarget =NULL; }//Finally offset the event to the target ' s coordinate system and       //Dispatch the event.        Final floatXC = Scrolledxfloat-(float) Target.mleft;Final floatYC = Scrolledyfloat-(float) Target.mtop; Ev.setlocation (XC, YC);if((Target.mprivateflags & cancel_next_up_event)! =0) {ev.setaction (motionevent.action_cancel);             Target.mprivateflags &= ~cancel_next_up_event; Mmotiontarget =NULL; }//If the action_move is not intercepted, Action_down will send the touch event directly to target       returnTarget.dispatchtouchevent (EV); }

1, dispatchtouchevent role: Determine whether the event by onintercepttouchevent to intercept processing.
When returning super.dispatchtouchevent, the flow of events is determined by onintercepttouchevent.
Returns false, the event is continued to be distributed, and the Action_down is processed internally only
Returns True when the distribution event is not continued and all events are handled internally (ACTION_DOWN,ACTION_MOVE,ACTION_UP)

2, Onintercepttouchevent action: Intercept event, used to determine whether the event is transmitted to the child view
Returns true when intercepted and handed over to their own ontouchevent processing
Returns false when intercepted and handed over to the child view to handle

3. Ontouchevent Effect: The event eventually arrives at this method
Returns True when all events are handled internally, in other words, subsequent events will continue to be passed to the view's ontouchevent () processing
When False is returned, the event is passed up, accepted by Ontoucevent, and the event disappears if ontouchevent in the top view also returns false.

5. Summary
  • If ViewGroup finds a view that can handle the event, it is handed to the child view processing, and its ontouchevent will not be triggered;

  • The Onintercepttouchevent (EV) method can be used to intercept the event of a child view (that is, return true), and the event is handed to itself, and the corresponding Ontouchevent method is executed.

  • Child view can be called by GetParent (). Requestdisallowintercepttouchevent (True); Prevents ViewGroup from intercepting its move or up event;

  • After a click event is generated, it is passed as follows:
    Activity->window->view. After the top view receives the event, the event is distributed according to the appropriate rules. If a view's Ontouchevent method returns false, it will be handed over to the parent container's Ontouchevent method, and if all of the view does not handle the event, it is referred to the activity's ontouchevent for processing.

  • If a view starts processing an event and if he does not consume the Action_down event (that is, Ontouchevent returns false), the same sequence of events, such as the next Action_move, will not be handed over to the view processing.

  • ViewGroup does not intercept any events by default.

  • such as TextView, imageview these non-container view, once the event is accepted, the Ontouchevent method is called, they do not have a onintercepttouchevent method. Normally, they consume events (return true), unless they are not clickable (both clickable and longclickable are false), then they are handled by the ontouchevent of the parent container.

  • Click on the event distribution process below Dispatchtouchevent-->ontouchlistener Ontouch method-->ontouchevent–>onclicklistener the OnClick method. That is, we usually call the Setonclicklistener, the priority is the lowest, so, ontouchevent or Ontouchlistener Ontouch method if return true, do not respond to the OnClick method ...

[Android] View and ViewGroup event distribution mechanism

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.