Understanding Touch Control and Events in Android
Almost all phones nowadays running Android are touch-controlled. There are very few phones which are not touch-based.
In this blog, we are going to talk about how we can handle touch events in Android. This is like, understanding how we can work around with touch controls and touch events when we tap on our screen.
We are going to discuss how touch events in Android work internally for any view.
So, how do the input events actually work and what exactly happens when we touch our screen when we have a ViewGroup having different views inside it?
In this case, we are going to talk about a case where we have a LinearLayout containing a button like,
What we are to going to discuss in the blog is,
- What happens when we touch the screen?
- How do we intercept touch events?
- How touch is handled?
- What are the touch events we majorly work within Android for handling the touch control?
What happens when we touch the screen?
So, when we touch the screen the activity's view gets the touch event notification first also known as
DecorView
in Android. Now, we generally don't work with the touch of
DecorView
. So, the touch gets transferred to the ViewGroup and subsequently to its children in the XML file.
But how can we transfer the touch event trigger?
In Android, the ViewGroup transfers the touch event from top to bottom in the hierarchy of ViewGroup to its children using
dispatchTouchEvent()
.
How do we intercept touch events?
First when we perform a touch action,
Then ViewGroup gets the touch event, and then it is intercepted in the ViewGroup itself using
onInterceptTouchEvent()
.
If on intercepting if we return
true
then the touch event is
not
passed to its children and if we pass
false
, the Android eco-system gets notified that the ViewGroup wants to dispatch the event to its children, in our case it is a button.
In general, if returning true, it means we have handled the event in the ViewGroup itself, no need to dispatch to its children.
Now, as the button we have, is the last view in our view tree. So, it won't be able to pass the touch event to its children anymore as it has none. So, in button, we would have our last onInterceptTouchEvent being called.
Intercepting of the event can only happen in ViewGroups and not Views.
Now, let's discuss how the touch is handled in the view.
How touch is handled in the view?
When dispatching the touch event from top to bottom in the view hierarchy, we need to see at which position of the tree we need to handle the touch on the view.
When handling the dispatching the event, the top position of the hierarchy takes the lead, but when it comes to handling the touch the child views using onTouchEvent are always the first, and then it keeps moving towards the ViewGroups.
Touch event works just like the dispatching of the events but in the reverse order from child to parent.
Let's say if we dispatch the event from ViewGroup and intercept the event there, it depends on the return value (true/false) that shall the touch of the view be handled on the ViewGroup or the children.
So in our case, if the
onTouchEvent
of
Button
returns
true
, then it means that it has been handled and then, it will
not
go to the
LinearLayout
.
What are the touch events we majorly work within Android for handling the touch control?
When we get the touch event, it gets handled by
onTouchEvent
which also has a parameter of type
MotionEvent
.
fun onTouchEvent(event: MotionEvent)
All the task performed regarding the touch has its reference in the event parameter. We can have the coordinates like X and Y points on the screen of the point on the touch.
It even has the actions in it, like let's see if we tap on the screen then MotionEvent.ACTION_DOWN is called and when we lift the touch MotionEvent.ACTION_UP is called.
Even dragging a finger on the screen, the action is MotionEvent.ACTION_MOVE.
So, the flow on the view happens is when we want to tap the button,
Activity -> dispatchTouchEvent (LinearLayout) -> dispatchTouchEvent(Button) -> onTouchEvent(Button).
and when we don't want to tap the button but want to handle the click on LinearLayout, the flow would be,
Activity -> dispatchTouchEvent (LinearLayout) -> dispatchTouchEvent(Button) -> onTouchEvent(Button) (will return false) -> onTouchEvent(LinearLayout).
Summary
To summarise everything how to work around touch control is,
- When working on touch events we start by clicking a view and removing the gesture (in our case our finger/stylus) then MotionEvent.ACTION_DOWN and MotionEvent.ACTION_UP is called respectively.
- When the initial touch happens on the ViewGroup and after intercepting when it moves to the child, then MotionEvent.ACTION_CANCEL gets called on the ViewGroup and the touch event dispatches to the children.
-
Now, everything depends on
onInterceptTouchEvent()
and its return value . Based on its return value the dispatchTouchEvent is dependent, that if returns true the dispatcher is canceled, and if it returns false then the dispatching of the touch event keeps going on until its used. -
And
onTouchEvent()
if the return value is true, then it means the touch is handled and if it returns false then it means the touch is not handled.
Now, we know how to control the touch event and how it works. This is very useful when designing the CustomViews and own view library.
You can check the implementation of how we can work with the onTouchEvent here.
Happy learning.
Team MindOrks.