Prevent Touch Event Theft in Android

In Android, touch events bubble up from child to parents as you would expect. However, a parent can choose to intercept all touch events targeted for one of its children and decide to veto dispatch of the event to the child. Widgets that scroll, like ListView or ExpandableListView, routinely do this to implement scrolling. But, this can lead to all kinds of nasty problems when you embed a child that needs touch gesture within such a parent. For example, adding a ViewPager within a ListView will cause the ViewPager to not work all that well.

Many on the Internet will tell you that you shouldn’t be embedding a ViewPager within a ListView. Well, I respectfully disagree. Many top class apps do exactly that. Amazon Video and Netflix are to name a few.  So, how can we fix this problem? First, let’s go through the theory. A parent needs to return true from onInterceptTouchEvent to deny dispatching touch events to its children. A child can counter that by calling requestDisallowInterceptTouchEvent(true) for it’s parent View. When a child does that, a parent can no longer use onInterceptTouchEvent() to steal touch events from the child.

First, write this method:

public static void disableTouchTheft(View view) {
    view.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            view.getParent().requestDisallowInterceptTouchEvent(true);
            switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_UP:
                view.getParent().requestDisallowInterceptTouchEvent(false);
                break;
            }
            return false;
        }
    });
}

The View passed to the disableTouchTheft() method is the child (such as a viewPager) that doesn’t want its parent to steal its touch events. For all touch events it asks its parent to not intercept the event. For ACTION_UP event, the child releases the lock and allows the parent to intercept.

Advertisements

13 thoughts on “Prevent Touch Event Theft in Android

  1. You can’t even believe how much you helped me out right now! This is the slickest and best solution i’ve found – and i stumbled here just due to the fact that stackoverflow was down 😉 Thanks Mate!

  2. It should be noted that ViewGroups naturally reset the FLAG_DISALLOW_INTERCEPT flag, so listening for the ACTION_UP event and resetting the flag isn’t needed.

  3. Your solution doesn’t work at all for my scrollbar.
    Mine is create a custom view and add

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
    return false;
    }

    then the scrollview doesn’t steal my touch event anymore.

    • This blog post is very old. Things might have changed since then. I personally use RecyclerView if I need to embed a horizontally scrollable section in the app.

  4. Amazing amazing, awesome, loved it. It just turned out to be the best solutions for tons of my headache due to touch theft on my RecyclerView childs. Since three to four days i was not able to find the solution. Actually I am a newbie to android. Many thanks to your simple but helpful post. Thanks again.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s