This is Part 2 of my Android Touch System series. Part 1 does a deep dive into touch functions (onDispatchTouchEvent(), onInterceptTouchEvent(), onTouchEvent()) and how they affect the way touch events flow through the views hierarchy. This post will show visual examples of how these functions work.
The visualizations are based on a sample app I made with subclasses of Activity, FrameLayout, ScrollView, and View that print a log message whenever the functions are called. You can find it on Github and play around with your own implementations of the touch functions.
Here’s a quick recap of the functions covered inPart 1:

Scenario 1
Tap on View B. None of the views consume it
Let’s revisit the visualization from Part 1. Note that View B is added to after View A, so its dispatchTouchEvent() gets called first; ViewGroups pass touch events to their children in reverse order in which they were added.

Scenario 2
Tap on View B. View B’s onTouchEvent() returns true
Since none of View B’s ancestors intercept taps, the event is passed all the way to its onTouchEvent(). Since it returns true, the event stops there and none of the other views’ onTouchEvent()s gets called.

Scenario 3
Tap on View A. None of the views consume it
This is similar to Scenario 1, except since the touch isn’t inside View B’s bounds, FrameLayout passes it to View A directly.

Job Offers
Scenario 4
Scroll on View B. ScrollView intercepts it and shows scrolling
ScrollView’s onInterceptTouchEvent() returns true, so its child views aren’t notified of the event. ScrollView’s onTouchEvent() is called. It also returns true, so the event stops there.

Scenario 5
Scroll on View B. View B overrides dispatchTouchEvent() and calls parent.disallowTouchEvent(true). View B’s onTouchEvent() also returns true. No scrolling occurs.
All of View B’s ancestors’ onInterceptTouchEvent()s are ignored, and the event stops at View B’s onTouchEvent(). ScrollView never scrolls.

Scenario 6
Scroll on View B. View B overrides dispatchTouchEvent() and calls parent.disallowTouchEvent(true). View B’s onTouchEvent() returns false. ScrollView scrolls.
All of View B’s ancestors’ onInterceptTouchEvent()s are ignored, but since View B’s onTouchEvent() doesn’t handle the event, it gets passed up to the ancestors’ onTouchEvent()s. ScrollView’s onTouchEvent() is called and returns true, signifying it handled the event. We see a scroll and the event stops there.

References
The main resources I used for this article are:
- Mastering the Android Touch System talk
- Mastering the Android Touch System article
- The source code for MotionEvent, View, ViewGroup, ScrollView, and Activity
Here’s the link to Part 1: Touch Functions and the View Hierarchy again. I plan to publish two more articles in this series: Part 3 will cover listeners (GestureDetector, OnClickListener, OnTouchListener, etc) and Part 4 will look at touch in Jetpack Compose. Stay tuned!
Thanks to Russell and Kelvin for their valuable editing and feedback ❤️


