Android Using a Scrollable ViewGroup Like ScrollView, ListView or GridView In a ScrollView With requestDisallowInterceptTouchEvent()

There are times when you want to have a scrollable ViewGroup like a ViewPager or a ListView or a GridView inside another scrollable ViewGroup like a ScrollView. You could have various combinations like a ViewPager in a ListView, a ViewPager and a ListView inside a ScrollView (this is what I had to do in my Android app), etc. in your application.

The Problem

All sounds nice, but why are we talking about it ? We talk about it because at times having a scrollable view group inside another scrollable control can cause issues. You’ll come across certain forum threads, blog posts, SO answers, etc. that mentions not using such a combination and instead find workarounds like put a ViewPager inside a ListView as a header and so on. If they work for you, then great, but if you really want to have such aforementioned combinations without any problem then there’s a little trick (or a solution) that might help us in most cases.

What's the one thing every developer wants? More screens! Enhance your coding experience with an external monitor to increase screen real estate.

Before discussing the solution, let’s understand what the problem is and why it occurs. So let’s say you have a ListView inside a ScrollView, then when the user tries to scroll through the ListView he’s unable to do that but can scroll fine through the ScrollView itself. The reason behind this (or similar cases) is that, the onInterceptTouchEvent() method of the ScrollView intercepts the gesture events. Hence, the ListView never gets those events which prevents it from processing them and causing scrolls on it while the scrolling occurs on the ScrollView.

The expected behaviour is when the user scrolls the parent (ScrollView), it should just scroll that and when the user scrolls the child (ListView), then the scroll events should process on the child. Generally that doesn’t happen in Android when a scrollable element (child) is inside another scrollable component (parent). Obviously the parent should be big enough to be able to scroll, then only will this problem occur (according to my tests).

Note: I’ve tried to explain the entire flow of the touch events in such cases here which I suggest you to understand first.

The Solution

The solution is really simple. We can call requestDisallowInterceptTouchEvent() (on the parent) and pass it true as the argument. What this’ll do is, it’ll prevent the parent (ScrollView) and ancestors from intercepting events and let the child (ListView or a ViewPager) handle them properly. This way the child will scroll just fine.

Here’s a sample code:

listView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        scrollView.requestDisallowInterceptTouchEvent(true);

        int action = event.getActionMasked();

        switch (action) {
            case MotionEvent.ACTION_UP:
                scrollView.requestDisallowInterceptTouchEvent(false);
                break;
        }

        return false;
    }
});

You’ll wonder why I called requestDisallowInterceptTouchEvent(false) again and passed false to it. That’s to revert to the normal state (that we were in before scrolling), to prevent unexpected behaviour if the scrollView has more scrollable elements other than listView or some other use case that we can’t probably think of right now. It’s usually recommended to do this.

Hope that helps!

Author: Rishabh

Rishabh is a full stack web and mobile developer from India. Follow me on Twitter.

1 thought on “Android Using a Scrollable ViewGroup Like ScrollView, ListView or GridView In a ScrollView With requestDisallowInterceptTouchEvent()”

Leave a Reply

Your email address will not be published. Required fields are marked *

*