Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent Swiping of ViewPager2 when onTouch of inner view

I have a ViewPager2 with a fragment inside,

in the fragment, I have a custom view with certain touch logic that involves moving the finger.

how do I prevent the ViewPager from swiping while the inner view intercepts the touch event?

override fun onTouchEvent(event: MotionEvent?): Boolean {
    if (event?.action == MotionEvent.ACTION_DOWN || event?.action == MotionEvent.ACTION_MOVE) {
       //Do some stuff here
    }
    return true
}

while swiping this view the view pager still swipes to other pages.

like image 854
Vasili Fedotov Avatar asked Feb 20 '20 21:02

Vasili Fedotov


People also ask

How do I turn off swipe in viewpager2?

You can easily do that by creating a custom class inherits from viewPager and override two methods: “onTouchEvent()” and “onInterceptTouchEvent()” and return true or false to disable and enable the swiping on certain touch events i.e say swiping. // Detects the direction of swipe. Right or left.

How to handle touch event in android?

You can react to touch events in your custom views and your activities. Android supports multiple pointers, e.g. fingers which are interacting with the screen. The base class for touch support is the MotionEvent class which is passed to Views via the onTouchEvent() method. you override the onTouchEvent() method.

What is touch slop?

"Touch slop" refers to the distance in pixels a user's touch can wander before the gesture is interpreted as scrolling.

How to intercept touch event android?

Views can intercept the event by overriding onInterceptTouchEvent() . If onInterceptTouchEvent() returns true , it means the event was consumed and won't be passed onto descendent views. If it returns false , it means the view acknowledged the event but continued passing it down.


2 Answers

Set OnTouchListener for inner view. In onTouch() method, call:

viewPager.requestDisallowInterceptTouchEvent(true)

ViewPager handles its swiping motion in onInterceptTouchEvent(). Above code prevents ViewPager from calling onInterceptTouchEvent(). When you're swiping, ViewPager returns true in onInterceptTouchEvent() which also prevents touch events to be passed to child views. Therefore disallowing intercept allows child views to handle touch events.

Set back to false when the inner view is not being touched.

From my experience, onInterceptTouchEvent() prevents onTouchEvent(). It does not prevent OnTouchListener. So the key here is to set up OnTouchListener for the inner view.

like image 167
Loremar Marabillas Avatar answered Oct 26 '22 12:10

Loremar Marabillas


To fix this, you should extend the ViewPager2 like this:

fun ViewPager2.reduceDragSensitivity() {
    val recyclerViewField = ViewPager2::class.java.getDeclaredField("mRecyclerView")
    recyclerViewField.isAccessible = true
    val recyclerView = recyclerViewField.get(this) as RecyclerView

    val touchSlopField = RecyclerView::class.java.getDeclaredField("mTouchSlop")
    touchSlopField.isAccessible = true
    val touchSlop = touchSlopField.get(recyclerView) as Int
    touchSlopField.set(recyclerView, touchSlop * 6) // "6" was obtained experimentally
}

and call reduceDragSensitivity. So the viewpager2 will look like this:

view_pager.reduceDragSensitivity()

Example: https://github.com/ali-sardari/ViewPager2Example

enter image description here

like image 37
Ali Sardari Avatar answered Oct 26 '22 12:10

Ali Sardari