Android View Event distribution mechanism detailed _android

Source: Internet
Author: User

Android development, touch control everywhere. For some students do not see the source code, how many of this will have some doubts. View event distribution mechanism, not only in doing business requirements will encounter these problems, in some interview written questions are often asked, it is commonplace. I've also seen a lot of people write this article, not too long-winded is too vague, there are some in the details of the dispute is also written, so once again to reorganize this piece of content, 10 minutes to let you understand the view event distribution mechanism.

Plainly these touch event distribution mechanisms are to figure out three methods, Dispatchtouchevent (), Onintercepttouchevent (), Ontouchevent (), And these three methods are stacked with n viewgroup and view, and the complex structure can be split into 1 viewgroup+1 view.

In fact, viewgroup and view are the same, view just without the child container, nature does not exist interception problem, dispatch is also very simple, so understand the viewgroup actually understand the almost.

Three key methods

public boolean dispatchtouchevent (motionevent ev)

View/viewgroup handles the initiator of an event distribution, View/viewgroup receives a touch event that first is tuned, and then determines whether to handle the interception or distribute the event to the child container in the method

public boolean onintercepttouchevent (motionevent ev)

ViewGroup dedicated, this method can reach the direction of distribution of control events, generally can be judged in the method of the event to ViewGroup or it continues to pass to the child container, is the best place to handle event conflicts

public boolean ontouchevent (Motionevent event)

The real handler for the touch event, and the last of each event will be handled here.

Core issues

The difficulty of the time distribution mechanism where I find it hard to place the following points: Three methods invoke the rule, determine the object that handles the event, and resolve the event conflict.

Event-Passing rules

A general click will have a series of motionevent, can be simply divided into: down->move->....->move->up, when an event distribution to ViewGroup, the above three methods between the The order of invocation in ViewGroup can be expressed in a simple code

Motionevent Ev;//down or move or up or others
... Viewgroup.dispatchtouchevent (EV);

public boolean dispatchtouchevent (motionevent ev) {
 Boolean isconsumed = false;
  if (onintercepttouchevent (EV)) {
   iscousumed = this.ontouchevent (EV);
  } else{
   isconsumed = childview.dispatchtouchevent (EV);
  }
  return isconsumed;
}

The return of the result true indicates that the event was processed, and return false indicates that no processing was made. The above code is easy to understand, it seems very simple, a word can be summed up, ViewGroup received the event call after the dispatch, in the dispatch first check whether to intercept, if the interception is ViewGroup eat events, otherwise to have the processing capacity of the child container processing.

However, simple to simple, written in order to facilitate understanding, ViewGroup event processing process is certainly not so simple, here ignore a lot of details, and then continue to add. Back to the above, a series of events we often deal with is generally a down, a number of move and a up, the above pseudo code is no way to solve these problems to the perfect solution, directly to see ViewGroup's dispatchtouchevent.

Onintercepttouchevent Call Condition

Final Boolean intercepted;
if (actionmasked = = Motionevent.action_down
    | | | mfirsttouchtarget!= NULL) {
  final Boolean disallowintercept = (MG Roupflags & Flag_disallow_intercept)!= 0;
  if (!disallowintercept) {
    intercepted = onintercepttouchevent (EV);
    Ev.setaction (action); Restore action in case it is changed
  } else {
    intercepted = false;
  }
} else {
  //There are no t Ouch targets and this action are not a initial down
  //So this view group continues to intercept touches.
  intercepted = true;
}

Explain the code above, it looks like it's simple, but it's really simple. Before explaining the meaning of the intercepted representative, intercepted = = False indicates that the parent container ViewGroup temporarily does not intercept the event, the event has the opportunity to pass to the child view processing, returns TRUE indicates that the parent container directly intercepts the series event. The follow-up will not be passed to the child view anymore. Child view can only make this value false if it wants to get an event

The onintercepttouchevent call returns False (returns false to be passed to the child view, corresponding to the contents of the else in the pseudo code above). A better understanding of what is required for the event to be passed to the child container any one of the two conditions may be triggered (of course only possible):

One is down, the other is mfirsttouchtarget!. =null, that mfirsttouchtarget when not empty, interested students can see the ViewGroup addtouchtarget this method of the call time, Mfirsttouchtarget is here to assign value, the source code too long I will not post.

Mfirsttouchtarget is used to save the child view of the Action_down event that was consumed in the viewgroup, that is, the child.dispatchtouchevent (EV) in the above pseudo code in Action_ When down returns True view, as long as the dispatch of the child view returns true in Action_down, it is not null (this assignment occurs only in Action_down if the child viewaction__ Down the events that do not assign the following sequence to it are no longer, otherwise, the object is null if no child view is processed. Of course, to meet the above two conditions are not enough, must also meet the!disallowintercept.

Disallowintercept This variable is interesting, its value is mainly affected by the flag_disallow_intercept, this value can be set by the viewgroup of the child view, ViewGroup's Child view If you call Requestdisallowintercepttouchevent this method, it will change flag_disallow_intercept, Cause disallowintercept This value is ture, this situation will skip intercept, causing interception failure.

But it's not done yet, flag_disallow_intercept. This tag has a reset mechanism to view the ViewGroup source can be seen in the processing Motionevent.action_ When down will reset the mark to cause Disallowintercept to fail, is not insane, the above a paragraph such simple code has so many moths, here can also get a conclusion, Action_ You can certainly execute onintercepttouchevent when down.

So the interception of the intercepted is very important, can affect in the end is to let ViewGroup also son view handle this event.

The above two is likely to trigger the interception of the conditions said, then when the two conditions are not satisfied with the call will not be intercepted (interception is important, general ViewGroup return false so that the event can be passed to the child view, if the Action_ Down when you can not go to onintercepttouchevent and return false tell ViewGroup do not intercept, then the event can no longer be passed to the child view, so the interception is generally to go to, and generally return false so that the child view has the opportunity to deal with, this situation is generally in the Action_down after processing No child view when the Action_down and subsequent events, from the above pseudo code can be seen, At this time viewgroup himself is very passive, need to call ontouchevent to deal with, this pot on their own back.

Let's continue to say how mfirsttouchtarget and intercepted affect the direction of the event. Look at the Source:

if (!canceled &&!intercepted) {
....
if (actionmasked = = Motionevent.action_down
            | | (Split && actionmasked = motionevent.action_pointer_down)
            | | actionmasked = = motionevent.action_hover_move) {
 ....
 . for (child:childlist) {
   if (!child satisfied condition ...) {
     continue;
   }
   Newtouchtarget = Addtouchtarget (Child, idbitstoassign)//Here Give Mfirsttouchtarget assignment}}


Here you can see intercepted as false in Action_down to give the above Mfirsttouchtarget assignment, only mfirsttouchtarget is not empty to allow subsequent events to pass to the child view, Otherwise, the code subsequent events mentioned above can only be processed for the parent container.

Mfirsttouchtarget is the object of our subsequent events, it is easy to understand that if the object is not identified in the Action_down, then the subsequent events do not know who is passed to the parent container viewgroup processing, The real way to handle event delivery is dispatchtransformedtouchevent, and then look at the source:

Private Boolean dispatchtransformedtouchevent (Motionevent event, Boolean cancel,
      View child, int Desiredpointeridbits) {
   Final boolean handled;

    Canceling motions is a special case. We don ' t need to perform any transformations
    //or filtering. The important part is the action and not the contents.
    Final int oldaction = Event.getaction ();
    if (Cancel | | oldaction = = motionevent.action_cancel) {
      event.setaction (motionevent.action_cancel);
      if (child = = null) {
        handled = Super.dispatchtouchevent (event);
      } else {
        handled = Child.dispatchtouchevent (event);
      }
      Event.setaction (oldaction);
      return handled
    }

}

See, as long as the parameters of the child is empty, then ViewGroup call Super.dispatchtouchevent (event), Super is who, ViewGroup inherited from view, of course, view slightly, Who is the dispatch call to view? Certainly is own ontouchevent (later will say), therefore this finally has called ViewGroup own ontouchevent.

So when child! When =null, the call is the child's Dispatchtouchevent (event), if the child may be a view may also be viewgroup, if it is viewgroup continue to follow the above pseudocode to execute the event distribution, If it's also a view, call your own ontouchevent.

So, in the final analysis of the matter to whom, or with the passing of the child concerned, where this method is called, continue to see:

if (Mfirsttouchtarget = = null) {
        //No touch targets so treat this as a ordinary view.
        handled = dispatchtransformedtouchevent (EV, canceled, NULL,
            touchtarget.all_pointer_ids);
      } else {
     ...
     dispatchtransformedtouchevent (EV, Cancelchild,
                target.child, target.pointeridbits)
   }

That's why mfirsttouchtarget can affect the direction in which events are distributed. In this way, the entire pseudocode process is not very clear.

Here need to say two more words, in the above code flow, intercepted decided this event will not call ViewGroup's ontouchevent, When intercepted is true, the subsequent process calls ViewGroup's ontouchevent, and looking carefully at the code above, there are only two ture: the first is to call Intercepttouchevent to intercept the event, The other is that no child view can consume Actiondown. Only in both cases does the parent container ViewGroup itself
So the question is, think of a question: if the child view handles Action_down but the subsequent events return False, who is the last person to handle the event? You think about it, and we'll talk about that later.

Who's the baby?

Continue to expand our pseudocode, intercept conditions after the decision, decided to continue to pass the event to the child view, will call Childview.dispatchtouchevent (EV), the problem, where the children come, continue to see the source code

if (!canviewreceivepointerevents (child)
  | |!istransformedtouchpointinview (x, y, child, null)) {
   Ev.settargetaccessibilityfocus (false);
   Continue;
}

ViewGroup determines whether all of the child view is visible in the animation and whether it is in the range of clicks to determine if it is eligible to accept the event. Only the child who satisfies the condition can invoke dispatch.

Then look at the pseudocode, the last dispatch return ViewGroup isconsumed, if Isconsume = = true, description ViewGroup handled the Click event (ViewGroup itself or the child view processing), And this series of clicks will continue to be sent to this viewgroup to deal with, if isconsume = = False (Action_down), ViewGroup can not handle this click event, then the line of the category of click events and the ViewGroup missed. Will throw this event on its own parent container or activity processing.

After the pseudocode is finished, ViewGroup's event-passing rules are almost finished, so it's easy to see. View relative to the viewgroup is simpler, there is no interception method, dispatch basically directly call their own ontouchevent, deal with a little difficulty are wood.

Something that's not mentioned, but it's important.

The above explanation is very simple, is from a viewgroup+ a view start, the event distribution of the performer is viewgroup, the child container also has only one view, but the actual development of course not so simple, but do not be afraid, complex situation can be split into this mode, It's just that the hierarchy is a bit more complex, and the principle is the same.

Incidentally, add a few points:

When the user clicks on the screen and starts triggering a series of click events, the actual delivery process is: Activity (Phonewindow)->decorview->viewgroup->view, Before reaching ViewGroup, there was a Decorview, the event was transmitted from the activity, but these things are actually the same as the viewgroup principle, which can be seen as a big viewgroup, When it's decorview contains all the child view no one can consume the event (so that there is a loophole, you know what I mean) will eventually be handed over to the activity.

Event conflict resolution can be handled in several points according to the above principles. The easiest time to think of the process is in the onintercepttouchevent, such as when a horizontal sliding viewgroup is nested in a vertical sliding viewgroup, which can be used to determine in the action_move where the follow-up event should be passed to. , of course, can also according to the above labeled bit flag_disallow_intercept with the dispatchtouchevent to control the flow of events, it is relatively easy to think of, but see other great God, It is also possible to control the flow of events by sharing motionevent methods, that is, saving motionevent in the parent container and passing in the child view custom event-handling method at the right time to share events.

Any view that rejects the Action_down (return false) in a series of events will no longer be passed over by the subsequent events. But if other events are rejected, subsequent events can be transmitted, such as if the view is Action_move, the unhandled event will eventually be consumed by the activity (instead of the parent container of the view), but subsequent events will continue to be passed on to the view.

Reasonable use of action_cancel can control the lifecycle of a series of events and make event handling more flexible.

Understanding the mechanism of event distribution as long as you understand that the principle is basically enough, GitHub of a lot of awesome great gods. The distribution of the cool custom controls that can be seen on this basis, of course, there are a lot of things to expand and more in-depth content, because of the length of the relationship here is not wordy, The more important thing is to see the source code.
Finally send you a classic: paper on the end feel shallow, know this matter to preach!

The above is the Android view event distribution mechanism of data collation, follow-up to continue to supplement the relevant information, thank you for your support for this site!

Related Article

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.