Simple understanding of Android View event distribution and consumer source code
Preface:
During the development process, I felt that the View event was particularly brain-burning. After watching it for a long time, I thought I could understand it. I checked the reading notes of singwhatiwanna fans online in the middle, and felt like I was suddenly enlightened.
A very important learning method: simplify the complex and focus only on the key points.
The source code is a mess, don't expect every line of code to be understood. First of all, there is no need, and secondly, a lot of non-critical code will make you blur the really important parts.
The following are just the learning results of the senior sister. If you want to have a deep understanding, you still need to read the source code yourself.
2. Source code analysis
Since the source code is too long and it is not easy to understand, the senior sister won’t post it here because it is unnecessary.
The following is the simplified version of the senior sister.
(1)(event)
boolean dispatchTouchEvent(MotionEvent event) { int action = (); //Judge whether ViewGroup intercepts touch events. When ACTION_DOWN or a child View that can receive touch events is found hour,Depend ononInterceptTouchEvent(event)Decide whether to intercept。Other situations,Right nowACTION_MOVE/ACTION_UPand Not found to receivetouchThe child of the eventViewhour,Direct intercept。 boolean intercepted; if (action == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) { intercepted = onInterceptTouchEvent(event); } else { intercepted = true; } //If ViewGroup does not intercept touch events. Iterate through all subviews when ACTION_DOWN to find a touch event that can receive touch events sonView。If foundmFirstTouchTarget,And jump out of the loop。 boolean alreadyDispatchedToNewTouchTarget = false; if (!intercepted) { if (action == MotionEvent.ACTION_DOWN) { for (int i = childrenCount - 1; i >= 0; i--) { if (!canViewReceivePointerEvents(child) || !isTransformedTouchPointInView(x, y, child, null)) { continue; } if (dispatchTransformedTouchEvent(event, child)) { //Find mFirstTouchTarget newTouchTarget = addTouchTarget(child); alreadyDispatchedToNewTouchTarget = true; break; } } } } //Events and consumption. If no child View can receive touch events is found, the ViewGroup will handle and consume it by itself. If found, it can receive ittouchThe child of the eventView,则Depend onsonViewRecursive processingtouchEvents and consumption。 boolean handled = false; if (mFirstTouchTarget == null) { handled = dispatchTransformedTouchEvent(event, null); } else { if (alreadyDispatchedToNewTouchTarget) { handled = true; } else { while (touchTarget) { handled = dispatchTransformedTouchEvent(event, child); } } } return handled; } //The ViewGroup event is issued. If there is no child View that receives the touch event, the touch event will be sent by the parent class of the ViewGroup (i.e. View)ifchildNot empty,则交Depend onsonViewPostedtouchevent,sonViewCan beViewGrouporView。 boolean dispatchTransformedTouchEvent(MotionEvent event, View child) { boolean handled; if (child == null) { handled = (event); } else { handled = (event); } return handled; }
(2)(event)
//View's Touch event distribution. When an mOnTouchListener is set externally, it is first handed over to consume.If not consumed,Leave it toViewofonTouchEvent(event)Consumption。onTouchEventof实现是,If setmOnClickListener, Then execute()Click Event。The return value istrue,表示Consumption,否则未Consumption。 boolean dispatchTouchEvent(MotionEvent event) { boolean result = false; if (mOnTouchListener != null && (this, event)) { result = true; } if (!result && onTouchEvent(event)) { result = true; } return result; } boolean onTouchEvent(MotionEvent event) { performClick(); }
3. Summary
Summarize the event distribution and consumption process of ViewGroup:
The entire process includes 3 parts: determining whether to intercept -> Finding subviews that receive touch events -> Event dispatch and consumption
Determine whether to intercept:
(1) When ACTION_DOWN or non-ACTION_DOWN and a child view receiving touch event is found, the onInterceptTouchEvent(event) decides whether to intercept it
(2) When a child view that receives the touch event is not ACTION_DOWN, and no child View is found, it is indicated that the touch event needs to be intercepted.
Here we explain that there are two factors that affect whether the ViewGroup can intercept the touch event: whether the subView that receives the touch event and onInterceptTouchEvent(event). The process of finding the subView that receives the touch event only needs to be determined at ACTION_DOWN. If ACTION_DOWN is not found, then ACTION_MOVE and ACTION_UP will definitely not be found either, so the touch event is directly intercepted by ViewGroup. If a child View receiving touch event is found, in ACTION_MOVE and ACTION_UP, you still need to check the ViewGroup's onInterceptTouchEvent(event) to see if it is intercepted.
Find the child View that receives the touch event:
(1) Search in two cases: ACTION_DOWN and ViewGroup does not intercept.
(2) Search method: traverse all subViews. If the xy coordinates of the touch event are within a subView range of the ViewGroup, recursively distribute touch event operations for the subView. If a child View is found to handle the touch event (return true), a loop will jump out.
Here is the search criteria. To find the subView that receives touch events, obviously you only need ACTION_DOWN. There is no need to check both ACTION_MOVE and ACTION_UP, otherwise repeat the operation. If the ViewGroup has been blocked, obviously there is no need to consider how the subView is going.
Events and consumption:
(1) Two situations: ViewGroup issuance and consumption or ViewGroup's subview issuance and consumption
(2) If the subView that receives the Touch event is not found after the above two steps, then the ViewGroup will issue and consume. The issuance and call process is: -> -> -> onTouchEvent -> onClick
(3) If a child view receiving the touch event is found, the operation of recursive issuance and consumption of touch events is performed on the child view.
Replenish:
(1) In the source code, mFirstTouchEvent represents the child View that receives touch events
(2) Steps 2 and 3 both execute dispatchTransformedTouchEvent(event, child). In Step 2, it is just to find the child View that receives touch events. The main purpose of step 3 is to distribute and consume events. If the method has been executed for a subView in step 2, the execution will not be repeated in step 3. I personally understand, I don’t know if there is any error.
4. Conclusion
(1) Callback method
ViewGroup:dispatchTouchEvent -> onInterceptTouchEvent -> onTouchEvent
View: dispatchTouchEvent -> onTouch
(2) Call order
Action execution order: ACTION_DOWN -> ACTION_MOVE -> ACTION_UP
ViewGroup: dispatchTouchEvent -> onInterceptTouchEvent -> onTouchEvent()
View: dispatchTouchEvent -> onTouchEvent
Event distribution and delivery order: Parent View -> Child View
->
->
(After yes)
Event consumption delivery order: Child View -> Parent View
->
->
Personally, I understand that this transmission order is caused by dispatchTransformedTouchEvent, which is the recursive call, and the entrance to the entire event is.
The above is the sharing of articles on Android View event distribution and consumer source code. Regarding the distribution mechanism of Android view event, you can search for the corresponding articles on this site for extended learning!
Thank you for reading, I hope it can help you. Thank you for your support for this site!