ACTION_CANCEL while touching
This will happen when parent container will intercept your touch event. Any ViewGroup that overrides ViewGroup.onInterceptTouchEvent(MotionEvent) can do that (ScrollView or ListView for instance).
Proper way to deal with this is to call ViewParent.requestDisallowInterceptTouchEvent(boolean) method on your parent view once you think you need to keep the motion event.
Here's a quick example (attemptClaimDrag method is taken from android source code):
/**
* Tries to claim the user's drag motion, and requests disallowing any
* ancestors from stealing events in the drag.
*/
private void attemptClaimDrag() {
//mParent = getParent();
if (mParent != null) {
mParent.requestDisallowInterceptTouchEvent(true);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if (iWantToKeepThisEventForMyself(event)) {
attemptClaimDrag();
}
//your logic here
} else {
//your logic here
}
}
An ACTION_CANCEL
happens when a parent view takes over control of one of its children views.
Take a look at the documentation around ViewGroup.onInterceptTouchEvent(MotionEvent) method. From the link:
- You will receive the down event here.
- The down event will be handled either by a child of this view group, or given to your own
onTouchEvent()
method to handle; this means you should implementonTouchEvent()
to return true, so you will continue to see the rest of the gesture (instead of looking for a parent view to handle it). Also, by returning true fromonTouchEvent()
, you will not receive any following events inonInterceptTouchEvent()
and all touch processing must happen inonTouchEvent()
like normal. - For as long as you return false from this function, each following event (up to and including the final up) will be delivered first here and then to the target's
onTouchEvent()
. - If you return true from here, you will not receive any following events: the target view will receive the same event but with the action
ACTION_CANCEL
, and all further events will be delivered to youronTouchEvent()
method and no longer appear here
Need to disallow parent view to intercept the touch event:
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
when (event.action) {
MotionEvent.ACTION_DOWN -> {
(parent as? ViewGroup?)?.requestDisallowInterceptTouchEvent(true)
}
MotionEvent.ACTION_UP -> {
(parent as? ViewGroup?)?.requestDisallowInterceptTouchEvent(false)
}
else -> {
}
}
return true
}