onInterceptTouchEvent only gets ACTION_DOWN
I'll answer my own question: onInterceptTouchEvent only get called if the parent has a child view which returns "true" from onTouchEvent. Once the child returns true, the parent now has a chance to intercept that event.
onInterceptTouchEvent never receives action_move
It's a bit more complicated than that. First of all you need to override onTouchEvent()
and handle ACTION_DOWN
and MOVE
events there too. Then the following will happen.
ACTION_DOWN
event gets dispatched toonInterceptTouchEvent()
first. You should returnfalse
from there.- Now there are two cases:
- If there is no touchable view underneath
ACTION_DONW
event's location in the view tree, thenACTION_DOWN
event and all follow up events get dispatched toonTouchEvent()
. You must returntrue
from there. Only then you will receive follow up events sent toonTouchEvent()
method. Independently on whether you returntrue
orfalse
,onInterceptTouchEvent()
will not receive any follow up events anymore. - If there is a touchable view, then all events will be dispatched to
onInterceptTouchEvent()
(includingACTION_MOVE
events). You need to returntrue
from there, after you detected your gesture. Once you returntrue
from here, touchable view will receiveACTION_CANCEL
event and all further events will be dispatched toonTouchEvent()
method.
- If there is no touchable view underneath
Hope this helps.
Android onInterceptTouchEvent doesn't get action when have child view
The solution relates to this answer, as it is a result of the standard MotionEvent
handling.
In my code, when I touch the child LinearLayout
, the parent CustomViewGroup
doesn't intercept the MotionEvent
as it returns false, but my child LinearLayout
doesn't consume the MotionEvent
either, so the MotionEvent
is returned to the parent's onTouchEvent
, not onInterceptTouchEvent
.
On the other hand, when I touch my child ScrollView
, it consumes the MotionEvent
whether scrolling is enabled or disabled.
==> I think because Android doesn't generate a MotionEvent
again until the original one is either consumed or finished, so the parent CustomViewGroup
doesn't get the ACTION_MOVE
MotionEvent
via onInterceptTouchEvent
, instaed it is piped to onTouchEvent
when a child doesn't consume the MotionEvent
.
I found two solutions
Solution one
Forcibly make my LinearLayout
consume the MotionEvent
. This solution is available only when the child LinearLayout
has no touchable View
, ViewGroup
or Widget
. Like this:
LinearLayout mLinearLayout = (LinearLayout)findViewById(R.id.child_linear);
mLinearLayout.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
Solution two
Process the MotionEvent
returning from a child in my CustomViewGroup
's onTouchEvent
. Like this: (Just add else if case in onTouchEvent
).
case MotionEvent.ACTION_MOVE: {
if (mIsBeingDragged) {
mLastMotionY = event.getY();
mLastMotionX = event.getX();
pullEvent();
return true;
}
else if (isReadyForPull()) {
final float y = event.getY(), x = event.getX();
final float diff, oppositeDiff, absDiff;
diff = y - mLastMotionY;
oppositeDiff = x - mLastMotionX;
absDiff = Math.abs(diff);
ViewConfiguration config = ViewConfiguration.get(getContext());
if (absDiff > config.getScaledTouchSlop() && absDiff >
Math.abs(oppositeDiff) && diff >= 1f) {
mLastMotionY = y;
mLastMotionX = x;
mIsBeingDragged = true;
}
}
break;
}
While solution 1 is a quick fix for certain situations, solution two is the most flexible and reliable.
onInterceptTouchEvent's ACTION_UP and ACTION_MOVE never gets called
Your onInterceptTouchEvent
method is not called after ACTION_DOWN
event because you return true
in onTouchEvent
method. So all the other events are sent in onTouchEvent
and not in onInterceptTouchEvent
any more:
Using this function takes some care, as it has a fairly complicated
interaction with View.onTouchEvent(MotionEvent), and using it requires
implementing that method as well as this one in the correct way.
Events will be received in the following order: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 implement
onTouchEvent() 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 from onTouchEvent(), you will not receive any
following events in onInterceptTouchEvent() and all touch processing
must happen in onTouchEvent() like normal.
http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent)
Losing ACTION_DOWN parameters when InterceptTouchEvent
Just expose your mStartX to your activity. ( I know it not perfect but seems OK).
class ParentView extends ViewGroup (or some other viewGroup) {
int startX;
public int getStartX(){
return startX;
}
}
// After that just call getStartX() from your activity.
View.onTouchEvent only registers ACTION_DOWN event
You need to return true to get the following events after a down.
Related Topics
Android App Bundle Introduces Resource Not Found Crash in Android App
Firebase Database Points to Wrong Database Url
Gradle Sync Failed: Unable to Find Method
Read Data from SQLite Where Column Name Contains Spaces
Why Does Changing the Sum Order Returns a Different Result
How Is String Concatenation Implemented in Java 9
"Hello World" Android App with as Few Files as Possible, No Ide, and Text Editor Only
Getlocationonscreen() VS Getlocationinwindow()
Android Getintent().Getextras() Returns Null
Svg/Vector Graphical Objects Boolean Operations (Union, Intersection, Subtraction)