There are only two protagonists in Touch event distribution: ViewGroup and View. The Touch event of Activity actually calls the Touch event of its internal ViewGroup and can be processed directly as a ViewGroup.
View is in a ViewGroup, and a ViewGroup can also be in another ViewGroup. At this time, the internal ViewGroup is analyzed as a View.
There are three related events for ViewGroup: onInterceptTouchEvent, dispatchTouchEvent, and onTouchEvent. There are only two related events for View: dispatchTouchEvent and onTouchEvent.
First analyze the processing flow of ViewGroup: First, there must be a structural model concept: ViewGroup and View form a tree structure. The top level is the ViewGroup of Activity. There are several ViewGroup nodes below. Each node There are several ViewGroup nodes or View nodes underneath, and so on. As shown in the figure:
When a Touch event (touch event as an example) reaches the root node, that is, Active's ViewGroup, it will be delivered in sequence. The delivery process is to call Implemented by the dispatchTouchEvent method of the sub-View (ViewGroup). To put it simply, the ViewGroup traverses the sub-Views it contains and calls the dispatchTouchEvent method of each View. When the sub-View is a ViewGroup, it will continue to call the dispatchTouchEvent method of its internal View by calling the dispatchTouchEvent method of ViwGroup. The message delivery sequence in the above example is as follows: ①-②-⑤-⑥-⑦-③-④. The dispatchTouchEvent method is only responsible for event distribution. It has a boolean return value. When the return value is true, the sequential delivery will be interrupted. In the above example, if the dispatchTouchEvent of ⑤ returns true, then ⑥-⑦-③-④ will not receive this Touch event. Let’s take a simple version of the code to deepen our understanding:
/** * ViewGroup * @param ev * @return */ public boolean dispatchTouchEvent(MotionEvent ev){ ....//其他处理,在此不管 View[] views=getChildView(); for(int i=0;i<views.length;i++){ //判断下Touch到屏幕上的点在该子View上面 if(...){ if(views[i].dispatchTouchEvent(ev)) return true; } } ...//其他处理,在此不管 } /** * View * @param ev * @return */ public boolean dispatchTouchEvent(MotionEvent ev){ ....//其他处理,在此不管 return false; }
It can be seen here that ViewGroup’s dispatchTouchEvent is really performing “distribution” work, while View’s dispatchTouchEvent method does not perform distribution work, or it distributes The object is itself, deciding whether to hand over the touch event to itself, and the method of processing is the onTouchEvent event. In fact, the code actually executed by the dispatchTouchEvent method of the sub-View is like this
/** * View * @param ev * @return */ public boolean dispatchTouchEvent(MotionEvent ev){ ....//其他处理,在此不管 return onTouchEvent(event); }
Under normal circumstances, We should not override the dispatchTouchEvent method in a normal View because it does not perform distribution logic. When the Touch event reaches the View, all we have to do is handle it in the onTouchEvent event.
So, when is the onTouchEvent event of ViewGroup processed? When all sub-Views of the ViewGroup return false, the onTouchEvent event will be executed. Since ViewGroup inherits from View, it actually executes the onTouchEvent event by calling the View's dispatchTouchEvent method.
From the current situation, it seems that as long as we return false to all onTouchEvents, we can ensure that all sub-controls respond to this Touch event. But it must be noted that the Touch event here is limited to the Action_Down event, that is, the touch press event, while Aciton_UP and Action_MOVE will not be executed. In fact, a complete Touch event should consist of a Down, an Up and several Moves. Down mode is distributed through dispatchTouchEvent. The purpose of distribution is to find the View that really needs to handle the complete Touch request. When the onTouchEvent event of a View or ViewGroup returns true, it means that it is the View that actually wants to handle this request, and subsequent Aciton_UP and Action_MOVE will be handled by it. When the onTouchEvent of all child Views returns false, this Touch request is handled by the root ViewGroup, that is, the Activity itself.
Look at the improved dispatchTouchEvent method of ViewGroup
View mTarget=null;//保存捕获Touch事件处理的View public boolean dispatchTouchEvent(MotionEvent ev) { //....其他处理,在此不管 if(ev.getAction()==KeyEvent.ACTION_DOWN){ //每次Down事件,都置为Null if(!onInterceptTouchEvent()){ mTarget=null; View[] views=getChildView(); for(int i=0;i<views.length;i++){ if(views[i].dispatchTouchEvent(ev)) mTarget=views[i]; return true; } } } //当子View没有捕获down事件时,ViewGroup自身处理。这里处理的Touch事件包含Down、Up和Move if(mTarget==null){ return super.dispatchTouchEvent(ev); } //...其他处理,在此不管 if(onInterceptTouchEvent()){ //...其他处理,在此不管 } //这一步在Action_Down中是不会执行到的,只有Move和UP才会执行到。 return mTarget.dispatchTouchEvent(ev); }
ViewGroup also has an onInterceptTouchEvent. You can tell from the name that this is an interception event. This interception event needs to be explained in two situations:
1. If we return true in the onInterceptTouchEvent of a ViewGroup and the Action is Down for the Touch event, it means that all the operations issued by the ViewGroup will be Intercept it. In this case, mTarget will always be null, because mTarget is assigned a value in the Down event. Since mTarge is null, the ViewGroup's onTouchEvent event is executed. In this case, the ViewGroup can be treated directly as a View.
2. If we are in the onInterceptTouchEvent of a ViewGroup, all Touch events whose Action is Down return false, and the others return True. In this case, the Down event can be distributed normally. If the child Views all return false, then mTarget is still empty, no impact. If a sub-View returns true and mTarget is assigned a value, when Action_Move and Aciton_UP are distributed to the ViewGroup, a MotionEvent of Action_Delete will be distributed to mTarget, and the value of mTarget will be cleared at the same time, so that the next Action_Move (if the previous operation is not UP) will be handled by ViewGroup's onTouchEvent.
Situation 1 is used more often, while Situation 2 has not yet been used.
Summary from beginning to end:
1. There are only two protagonists in Touch event distribution: ViewGroup and View. ViewGroup contains three related events: onInterceptTouchEvent, dispatchTouchEvent, and onTouchEvent. View contains two related events: dispatchTouchEvent and onTouchEvent. Among them, ViewGroup inherits from View.
2. ViewGroup and View form a tree structure, and the root node is a ViwGroup contained within the Activity.
3. The touch event consists of Action_Down, Action_Move, and Aciton_UP. In a complete touch event, there is only one Down and Up, and there are several Moves, which can be 0.
4. When Acitivty receives the Touch event, it will traverse the sub-View to distribute the Down event. ViewGroup traversal can be viewed as recursive. The purpose of distribution is to find the View that actually handles this complete touch event. This View will return true in the onTouchuEvent result.
5. When a sub-View returns true, the distribution of the Down event will be stopped and the sub-View will be recorded in the ViewGroup. The subsequent Move and Up events will be handled directly by the sub-View. Since the sub-View is stored in the ViewGroup, in the multi-layer ViewGroup node structure, the upper-level ViewGroup saves the ViewGroup object where the View that actually handles the event is located: for example, in the structure of ViewGroup0-ViewGroup1-TextView, TextView returns true, which will be saved in ViewGroup1, and ViewGroup1 will also return true and be saved in ViewGroup0. When the Move and UP events come, they will first be passed from ViewGroup0 to ViewGroup1, and then from ViewGroup1 to TextView.
6. When all sub-Views in the ViewGroup do not capture the Down event, the onTouch event of the ViewGroup itself will be triggered. The way to trigger is to call the super.dispatchTouchEvent function, which is the dispatchTouchEvent method of the parent class View. When all sub-Views are not processed, the onTouchEvent method of Activity is triggered.
7.onInterceptTouchEvent has two functions: 1. Intercept the distribution of Down events. 2. Stop the delivery of Up and Move events to the target View, so that the ViewGroup where the target View is located captures the Up and Move events.
Supplement:
"Touch events are composed of Action_Down, Action_Move, and Aciton_UP. In a complete touch event, there is only one Down and Up, and there are several Moves, which can be 0.", here In addition, in fact, there may be 0 UP events.
The above is the entire content of this article. I hope it will be helpful for everyone to understand the Touch event distribution mechanism.
For more articles related to the 30-minute understanding of the Android Touch event distribution mechanism, please pay attention to the PHP Chinese website!