onInterceptTouchEvent only gets ACTION_DOWN
Asked Answered
L

3

30

Why do ViewGroup's only get ACTION_DOWN in the onInterceptTouchEvent? According to the docs, as long as false is returned it should receive all the event types. http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent%28android.view.MotionEvent%29 Point #3.

Sample code:

public class MainActivity extends Activity {

    private static final String TAG = MainActivity.class.getSimpleName();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new Container(this));
    }

    private class Container extends LinearLayout {

        public Container(Context context) {
            super(context);
            setBackgroundColor(0xFF0000FF);
        }

        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            Log.i(TAG, "onInterceptTouchEvent");
            int action = ev.getActionMasked();
            switch (action) {
            case MotionEvent.ACTION_DOWN:
                Log.i(TAG, "onInterceptTouchEvent.ACTION_DOWN");
                break;
            case MotionEvent.ACTION_MOVE:
                Log.i(TAG, "onInterceptTouchEvent.ACTION_MOVE");
                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                Log.i(TAG, "onInterceptTouchEvent.ACTION_UP");
                break;
            }
            return super.onInterceptTouchEvent(ev);
        }
    }
}
Lanner answered 8/11, 2012 at 6:40 Comment(0)
L
54

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.

enter image description here

Lanner answered 24/11, 2012 at 9:36 Comment(4)
How can the parent intercept the event if the child already dispatched it?Stravinsky
children do not dispatch touch events (normally). The touch events bubble from parent to children iteratively. Going down it's onInterceptTouchEvent and coming up it's onTouchEvent. It continues to bubble up until someone returns true.Lanner
If I have a View with an onTouchListener, that I add to a ViewGroup. This listener get's called, starts some behaviour, then returns false. After that the ViewGroup can "intercept" the event? If the code of the handler was already executed?Stravinsky
SelectionTracker of recycleview still gets called though even if you set setOnTouch listener on the ViewHolder. Does anyone know why that is?Sobersided
E
9

I get the same problem. I had read many posts about it:
onInterceptTouchEvent only gets ACTION_DOWN
onInterceptTouchEvent's ACTION_UP and ACTION_MOVE never gets called
onInterceptTouchEvent, onTouchEvent only see ACTION_DOWN
onInterceptTouchEvent never receives action_move

I also had read android doc:
http://developer.android.com/training/gestures/viewgroup.html
http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent(android.view.MotionEvent)

All answers are same. I tried many times, always not get onInterceptTouchEvent () be called if not down event.

I read source code, I guess that something is changed:

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
    if (mInputEventConsistencyVerifier != null) {
        mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
    }

    boolean handled = false;
    if (onFilterTouchEventForSecurity(ev)) {
        final int action = ev.getAction();
        final int actionMasked = action & MotionEvent.ACTION_MASK;

        // Handle an initial down.
        if (actionMasked == MotionEvent.ACTION_DOWN) {
            // Throw away all previous state when starting a new touch gesture.
            // The framework may have dropped the up or cancel event for the previous gesture
            // due to an app switch, ANR, or some other state change.
            cancelAndClearTouchTargets(ev);
            resetTouchState();
        }

        // Check for interception.
        final boolean intercepted;
        if (actionMasked == MotionEvent.ACTION_DOWN
                || mFirstTouchTarget != null) {
            final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
            if (!disallowIntercept) {
                intercepted = onInterceptTouchEvent(ev);
                ev.setAction(action); // restore action in case it was changed
            } else {
                intercepted = false;
            }
        } else {
            // There are no touch targets and this action is not an initial down
            // so this view group continues to intercept touches.
            intercepted = true;
        }


According above code, onInterceptTouchEvent(ev) is only be called when MotionEvent.ACTION_DOWN, this is what we tried and found. So, what I guess is, the code is changed, but doc not.

If you want spy or monitor all the events include those been sent to child views, you can override dispatchTouchEvent() like this:

@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    MyLog.d(MyLog.DEBUG, "dispatchTouchEvent(): "+event.getAction());
    if (isEnabled()) {
        MyLog.d(MyLog.DEBUG, "dispatchTouchEvent()2: "+event.getAction());

        processEvent(event);//here you get all events include move & up

        super.dispatchTouchEvent(event);

        return true; //to keep receive event that follow down event
    }
    return super.dispatchTouchEvent(event);
}

I have the runnable code at: https://github.com/maxyou/gesturebutton/blob/master/src/com/maxproj/gesturebutton/GestureButtonLayout.java

Equate answered 31/1, 2016 at 11:13 Comment(1)
Thanks a lot! I spent around 3 hours trying different solution, but this one really nice!Dentalium
S
3

dispatchTouchEvent, onInterceptTouchEvent, requestDisallowInterceptTouchEvent

[Touch event flow]

The official doc

Activity.dispatchTouchEvent(MotionEvent) - This allows your Activity to intercept all touch events before they are dispatched to the window.

ViewGroup.onInterceptTouchEvent(MotionEvent) - This allows a ViewGroup to watch events as they are dispatched to child Views. It is recursively function (from parent to parent)

ViewParent.requestDisallowInterceptTouchEvent(boolean) - Call this upon a parent View to indicate that it should not intercept touch events with onInterceptTouchEvent(MotionEvent).

Sopping answered 5/5, 2018 at 17:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.