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; ViewGroup
s 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 ❤️