Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to modify sensitivity of viewpager

Tags:

android

Does anyone know how to modify sensitivity of ViewPager?

Currently I use a ViewPager from android v4 support library to implement my own photo viewer.

However, default ViewPager is too sensitive, when my finger touch down on screen and moves by a very short distinct(maybe just 0.5cm). Then ViewPager will be toggled to scroll to next/previous photo view.

Is there any way to overwrite default behavior of ViewPager to decrease sensitivity?

Thanks to any response.

like image 640
Raymond Avatar asked Aug 27 '12 02:08

Raymond


4 Answers

For ViewPager2 extract and increase mTouchSlop using reflection.

    private 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*8)       // "8" was obtained experimentally
    }

Call this function from your view pager

val viewPager: ViewPager2 = view.findViewById(R.id.pager)
viewPager.reduceDragSensitivity()

Java version

private void reduceDragSensitivity() {
    try {
        Field ff = ViewPager2.class.getDeclaredField("mRecyclerView") ;
        ff.setAccessible(true);
        RecyclerView recyclerView =  (RecyclerView) ff.get(viewPager);
        Field touchSlopField = RecyclerView.class.getDeclaredField("mTouchSlop") ;
        touchSlopField.setAccessible(true);
        int touchSlop = (int) touchSlopField.get(recyclerView);
        touchSlopField.set(recyclerView,touchSlop*4);
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}

All credits to Alexander Shevelev and Mahmoud Shabat.

like image 181
secretshardul Avatar answered Nov 11 '22 11:11

secretshardul


While Pethő Jonatán has a good pointer to achieve better sensitivity, along with fling distance you may want to reduce minimumVelocity as well.

You may want to do this after initializing viewpager in onCreate:

 viewPager = findViewById(R.id.viewPager);
 Field mFlingDistance;
 Field mMinimumVelocity;

 try {
     mFlingDistance=ViewPager.class.getDeclaredField("mFlingDistance");
     mMinimumVelocity=ViewPager.class.getDeclaredField("mMinimumVelocity");

     mFlingDistance.setAccessible(true);
     mMinimumVelocity.setAccessible(true);

     //customize the values
     mFlingDistance.set(viewPager, 10);
     mMinimumVelocity.set(viewPager, 400);
    } catch (Exception e) {
      e.printStackTrace();
    }
like image 26
Tomin Avatar answered Nov 11 '22 10:11

Tomin


I've checked out ViewPager.java from src of compatibility library and seems there's not way to do it by xml or some setter. ViewPager has code like the following:

final float density = context.getResources().getDisplayMetrics().density;
mFlingDistance = (int) (MIN_DISTANCE_FOR_FLING * density);
mCloseEnough = (int) (CLOSE_ENOUGH * density);
mDefaultGutterSize = (int) (DEFAULT_GUTTER_SIZE * density);

As You can see, it uses it's internal constants for determination of fling distance and etc.

Good news are: You can copy ViewPager (here licence of it should be considered) to Your code and extend it e.g. to get fling distance from xml attribute.

like image 22
sandrstar Avatar answered Nov 11 '22 10:11

sandrstar


You can reflect the mFlingDistance field like this:

Field mFlingDistance;
mFlingDistance = ViewPager.class.getDeclaredField("mFlingDistance");
mFlingDistance.setAccessible(true);

// Set custom value:
mFlingDistance.set(mPager, 30);
like image 32
Pethő Jonatán Avatar answered Nov 11 '22 09:11

Pethő Jonatán