'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 1:[1]

Add this lines in yourlayout.xml:

android:clickable="true"
android:focusable="true"
android:focusableInTouchMode="true"

Try this block:

YOURActivityLayout.setOnTouchListener(new View.OnTouchListener() {  
        @Override
        public boolean onTouch(View arg0, MotionEvent arg1) {

            return true;//always return true 
        }
    });

Hope this will work

Solution 2:[2]

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)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 elliptic1