For a "We never produce code, we are just the nature code of the porter," the Code farmer. The touch mechanism of Android is always ambiguous, especially when it is required that some custom controls and Androide's own controls (such as Viewpager,listview,scrollview) are highly nested together.
It took a little time to comb and make a note. For a touch event from the user input to the actigvity to the outermost viewgroup in the sub view, the intermediate process may also be interspersed with multiple viewgroup,android in ViewGroup provides 3 ways to control the distribution, interception, and execution of the process. They were executed in the order of dispatchtouchevent (), Onintercepttouchevent (), Ontouchevent ().
I. Introduction to the main methods
Make a metaphor, all the events (can be regarded as food), to digest all right, first of all to judge the food at the table whether you like (dispatchtouchevent quite choose the food of the hand).
dispatchtouchevent (motionevent e):Determine the onintercepttouchevent and tag variables according to the parameter motioneventdisallowinterceptThe value (to be described later) to determine whether to pass the event to its own ontouchevent () method or to the child view or the child viewgroup to distribute again, or to dispose of it directly (calling its own Ontouchevent method).
When returningFalse, it was shown that the incident did not need to be distributed and killed the event in the cradle. :)
When the HuiTrue, indicating that the digestion of the Change event, go to the next step, you can see the flowchart (in the words of foodie, is that I did not eat full, and then a dozen small cage bag also no problem).
When food enters the mouth, for those who can't eat spicy. If the food is very very spicy, the tongue before entering the stomach can be judged whether the food is delicious and choose to swallow their own belly. Onintercepttouchevent here is quite with the human tongue, he is the second layer to judge whether food to swallow the organ.
Boolean onintercepttouchevent (motionevent e):Decide whether to intercept the next event so that the touchevent of the current view is processed.
When the Change method returnsTrue, the event stops distributing downward, and calls the current view's Ontouchevent method to handle it, (for those who do not like Parsley, one night in ramen if accidentally mixed with a hint of parsley, it must be spit).
When returned toFalse, the event will continue to be distributed to sub-view for digestion (and, of course, to get him into his stomach to treat himself well).
The Ontouchevent method is the stomach that really digests the food, and the real deal is in this place.
boolean ontouchevent (motionevent e) :The real message-handling function, his return value, directly affects the next time the event is passed back to the Ontouch method of the parent Class View.
When the return value isTrueIndicates that the current view has digested the event and does not require the parent view to continue digesting (do not call the parent class Ontouchevent) (Eat a good meat bag, not enough to eat, you can eat.)
When the return value isFalse, indicates that the current view can not digest the event, need the Parent View digest digestion (call the parent class Ontouchevent) (people encounter food is not good, sometimes also cause anti-acid, tell the human body, this is not delicious.)
The above process is the gradual process of the stomach from hand-to-mouth. Both the hand and the mouth can call the Onintercepttouchevent method to decide whether or not to pass.
But the Android touch process has an important way to do it:
void Requestdisallowintercepttouchevent (Boolean disallowintercept): The parameter of this method is a bool variable, Used to indicate whether a call to Onintercepttouchevent is required to determine whether to intercept.
If this tag is True, as it literally does-it is not allowed to call Onintercepttouchevent (), and the result is that all parent methods are not intercepted and the event is passed to the child view. This method belongs to ViewGroup and is a recursive method, which means that all disallowintercept of the parent class are set to Trueonce the call is made. That is, all the parent view of the current view does not call its own onintercepttouchevent () to intercept.
Code for the Requestdisallowintercepttouchevent method
public void Requestdisallowintercepttouchevent (Boolean disallowintercept) { if (disallowintercept = = ( Mgroupflags & flag_disallow_intercept)! = 0)) { //We ' re already in this state, assume We ancestors is too R Eturn; } Sets the current view's disallowintercept if (disallowintercept) { mgroupflags |= flag_disallow_intercept; } else { mgroupflags &= ~flag_disallow_intercept; } Recursive invocation, sets the parent class's disallowintercept if (mparent! = null) { mparent.requestdisallowintercepttouchevent ( disallowintercept); } }
Two. Summary
The following basic rules are:
1. If the current ViewGrouponintercepttouchevent ()After receiving the down event processing is completereturn False, the subsequent move, up, and other events will continue to be passed to the viewgroup before being passed to the ontouchevent () processing of the final target view as the down event.
If the current ViewGrouponintercepttouchevent ()After receiving the down event processing is complete REturn True, then the subsequent move, up, and other events will no longer be passed to Onintercepttouchevent (), but to the ViewGroup as the down event.ontouchevent ()Processing, note that the target view will not receive any events.
2. If the current ViewGroupontouchevent ()Returned thefalse, then the event will be passed to itsprevious level view of the ontouchevent ()Processing.
If the current ViewGroupontouchevent ()Returned thetrue, then subsequent events will continue to be passed toThe view's ontouchevent ()Processing.
3. If the currentview.dispatchtouchevent ()Returntrue, the message is no longer processed in the parent view, but only if the message is not intercepted by the parent view, and if the handler returns true during the entire touch message processing, we call it consumption of the touch event, and the subsequent parent view will no longer process the message.
Note: In the entire touch event process, from Action_down to Action_up, if the parent ViewGroup function Onintercepttouchevent Returns TRUE, the message will no longer be sent to the child view, The subdivision can be two cases, if Onintercepttouchevent returns True at Action_down, no message will be distributed to the child view, and the Onintercepttouchevent function will no longer be executed. if Onintercepttouchevent returns False when Action_down, and onintercepttouchevent==true in the back touch process, the parent ViewGroup will Action_ The cancel sends the child view and then no longer dispatches the message to the child view, and the Onintercepttouchevent function is no longer executed.
In many cases, the custom ViewGroup inherits the onintercepttouchevent simple rude return True, if the custom ViewGroup contains a button, you will find that the button's OnClick method does not execute. Should be to form a must first want the Tao a Action_down event, onintercepttouchevent thedown event also intercept, internal button naturally will not return to the onclick
Three. Flowchart Summary
If you look closely at the two classes of ViewGroup ontouchevent and intercepttouchevent, the whole process of onintercepttouchevent is not called ontouchevent, and vice versa, So how does onintercepttouchevent intercept the flow of events?
The answer is that in dispatchtouchevent, dispatchtouchevent controls whether the entire process is intercepted or passed on to the child view to continue digesting, Yes, he called Onintercepttouchevent and ontouchevent to judge.
Take a look at the flow chart as follows:
Four. Follow the source code, know the reason why
Now look at the most important viewgroup.dispatchtouchevent () source code, explore the following 3 rules of the principle of implementation
The whole process of dispatchtouchevent will be judged first.disallowinterceptValue, and then calls its own onintercepttouchevent to determine if interception, if intercepted, calls its ownontouchevent, if not intercepted, call the child view'sdispatchtouchevent, if the child view is a viewgroup, then it will be recursive to call their own Dispatchtouchevent method. If the child view is a simple view, it will call Ontouchevent, because the view can no longer contain the view, also naturally do not need to intercept, of course, there is no need to onintercepttouchevent method
@Override public boolean dispatchtouchevent (motionevent ev) {if (minputeventconsistencyverifier! = null) { Minputeventconsistencyverifier.ontouchevent (EV, 1); }//Check for interception. Final Boolean intercepted;//blocked tag variable if (actionmasked = = Motionevent.action_down | | mfirsttouchtarget ! = NULL) {Final Boolean disallowintercept = (Mgroupflags & flag_disallow_intercept)! = 0; if (!disallowintercept) {//calls its own onintercepttochevent to determine if it needs to intercept intercepted = On Intercepttochevent (EV); Ev.setaction (action); Restore action in case it is changed} else {intercepted = false; }} else {///There is no touch targets and the This action is a initial down/so this VI EW Group continues to intercept touches. intercepted = true; }//If not intercepted if (!canceled &&!intercepted) {if (actionmasked = = Motionevent.action_down | | (split && actionmasked = = Motionevent.action_pointer_down) | | actionmasked = = Motionevent.action_hover_move) {if (Newtouchtarget = = NULL && Childrencount! = 0) {final float x = Ev.getx (Actionindex); Final float y = ev.gety (Actionindex); Find a child that can receive the event. Scan children from front to back. Final view[] children = Mchildren; Final Boolean customorder = ischildrendrawingorderenabled (); Iterate through all the child view and call their event distribution method Dispatchtouchevent () for (int i = childrenCount-1; I >= 0; i--) { Final int childindex = Customorder? Getchilddrawingorder (Childrencount, i): i; Final View Child = Children[childindex]; if (!canviewreceivepointerevents (child) | |!istransformedtouchpointinview (x, y, child, NULL )) {continue; } Newtouchtarget = Gettouchtarget (child); Newtouchtarget represents the event pass view target, and when not empty, jumps directly out of the loop if (newtouchtarget! = null) { Newtouchtarget.pointeridbits |= idbitstoassign; Break } resetcancelnextupflag (child); Recursive call Sub View Distribution event method, if (Dispatchtransformedtouchevent (EV, FALSE, Child, Idbitstoassign)) { Mlasttouchdowntime = Ev.getdowntime (); Mlasttouchdownindex = Childindex; Mlasttouchdownx = Ev.getx (); Mlasttouchdowny = Ev.gety (); Set distribution target Newtouchtarget to current View Newtouchtarget = Addtouchtarget (Child, idbitstoassign); If the distribution result of the tag sub-view is true, the following code will not invoke the Ontouch method of the current view, which is why Rule 1 is generated Alreadydispat Chedtonewtouchtarget = true; Break }}}} if (Mfirsttouchtarget = = NULL) {//No touch targets so treat this as an ordinary view. handled = dispatchtransformedtouchevent (EV, canceled, NULL, touchtarget.all_pointer_ids); } else {//Dispatch to touch targets, excluding the new touch target if we already//dispatched to It. Cancel touch targets if necessary. Touchtarget predecessor = NULL; Touchtarget target = Mfirsttouchtarget; while (tarGet! = null) {final touchtarget next = Target.next; If Alreadydispatchedtonewtouchtarget is set to True, the following dispatchtransformedtouchevent is not performed//alreadydispatchedton Ewtouchtarget is determined by the Ontouch return value of the child view, if (Alreadydispatchedtonewtouchtarget && target = = Newtouchtarget) {handled = true; } else {Final Boolean cancelchild = Resetcancelnextupflag (target.child) | | intercepted; Perform its own touch event, if (Dispatchtransformedtouchevent (EV, Cancelchild, target.ch ILD, target.pointeridbits)) {handled = true; } if (Cancelchild) {if (predecessor = = null) {Mfirs Ttouchtarget = Next; } else { Predecessor.next = Next; } target.recycle (); target = next; Continue }} predecessor = target; target = next; } } }
Look again.view of the Dispatchtoucheventmethod, which is very simple, basically calls the Ontouch () method and returns the result.
public boolean dispatchtouchevent (Motionevent event) { if (minputeventconsistencyverifier! = null) { Minputeventconsistencyverifier.ontouchevent (event, 0); } //... if (Ontouchevent (event)) {//view's dispatchtouchevent is very simple, it calls down its own Ontouch event and returns the result. This result directly affects whether or not the subsequent event///continues to pass return true;} } //... return false;}
So, figuring out the 3 main methods, and straightening out the return value of each method, clearly knowing the effect of the return value on other methods is the key to figuring out the touch model. Can do, the need to change again, you can also make the interaction of the app well.