Search code examples
androidandroid-layoutandroid-viewpagertouchandroid-view

Expanding the touch area of a ViewPager


My App uses the following ViewPager:

Screenshot

The ViewPager has the same width as the display.

I added margins to the ViewPager in xml so that I can see the left(blue) and right(gray) page. As a result everything works fine but I can only touch onto the green area to move the pages.

I want to expand the touch area to the whole screen so that I am able to touch anywhere to move the ViewPager.

I tried to add a TouchDelegate:

binding.pagerContainer.post {
        val rect = Rect()  
        binding.touchArea.getHitRect(rect)
        binding.pagerContainer.touchDelegate = TouchDelegate(rect, binding.viewPager)
    }

And in the xml:

 <FrameLayout
        android:id="@+id/pager_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:clipChildren="false">

        <android.support.v4.view.ViewPager
            android:id="@+id/viewPager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center"
            android:layout_marginBottom="150dp"
            android:layout_marginLeft="70dp"
            android:layout_marginRight="70dp"
            android:layout_marginTop="150dp"
            android:clipChildren="false"/>

        <View
            android:id="@+id/touchArea"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:alpha="0">
        </View>
    </FrameLayout>

The Rect has the correct size. I am posting a Runnable to be sure that the views are laid out. I read the documentation of the TouchDelegate.

I have no idea why it's not working.


Solution

  • OK. I think I have it this time. After some research here and here, I've come up with this answer. Instead of trying to expand the area of ViewPager with TouchDelegate, I've re-routed touch events from the FrameLayout to the ViewPager. 1st, make your own FrameLayout

    public class MyFrameLayout extends FrameLayout {
    
        // make sure to include all the necessary constructors here
        // with calls to super
    
        // only need to override 1 method
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            ViewPager pager = null;
            int count = getChildCount();
            for(int i=0; i<count; i++) {
                if(getChildAt(i) instanceof ViewPager) {
                    pager = (ViewPager)getChildAt(i);
                    break;
                }
            }
            if(pager != null) {
                return pager.onTouchEvent(event);
            }
            return super.onTouchEvent(event);
        }
    }
    

    If you know that the ViewPager will always be in the same place in the FrameLayout, the onTouchEvent() can be simplified to

        ViewPager pager = (ViewPager)getChildAt(0); 
        return pager.onTouchEvent(event);
    

    Then you use your custom FrameLayout in the layout file

     <your.package.name.MyFrameLayout
        android:id="@+id/pager_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        etc. etc.
    

    I've tested it and this does it for me. Hope it works for you.