Expanding the touch area of a ViewPager

Viewed 820

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.

3 Answers

My viewpager had a view behind it acting as a background. I noticed that touch events sent to the inactive items to the left and right of the active item in the viewpager were sent to the background view. That gave me the idea to intercept touches there and use the viewpager's fake drag api.

I built an extension function for ViewPager2 like this:

fun ViewPager2.receiveFakeDragsFrom(view: View) {
    view.setOnTouchListener { _, event ->
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                requestDisallowInterceptTouchEvent(true)
                beginFakeDrag()
                true
            }
            MotionEvent.ACTION_MOVE -> {
                if (event.historySize > 0) {
                    fakeDragBy(
                        event.x - event.getHistoricalX(0)
                    )
                }
                true
            }
            MotionEvent.ACTION_UP -> {
                endFakeDrag()
                requestDisallowInterceptTouchEvent(false)
                performClick()
                true
            }
            else -> {
                false
            }
        }
    }
}

Then in my fragment while setting up the viewpager, I just called that function with the background view as the argument:

myViewPager.receiveFakeDragsFrom(vpBackgroundView)
Related