Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Slowing speed of Viewpager controller in android

Tags:

android

Is there any way to slow the scroll speed with the viewpager adaptor in android?


You know, I've been looking at this code. I can't figure out what I'm dong wrong.

try{      Field mScroller = mPager.getClass().getDeclaredField("mScroller");      mScroller.setAccessible(true);      Scroller scroll = new Scroller(cxt);     Field scrollDuration = scroll.getClass().getDeclaredField("mDuration");     scrollDuration.setAccessible(true);     scrollDuration.set(scroll, 1000);     mScroller.set(mPager, scroll); }catch (Exception e){     Toast.makeText(cxt, "something happened", Toast.LENGTH_LONG).show(); }  

It doesn't change anything yet no exceptions occur?

like image 747
Alex Kelly Avatar asked Nov 16 '11 16:11

Alex Kelly


2 Answers

I've started with HighFlyer's code which indeed changed the mScroller field (which is a great start) but didn't help extend the duration of the scroll because ViewPager explicitly passes the duration to the mScroller when requesting to scroll.

Extending ViewPager didn't work as the important method (smoothScrollTo) can't be overridden.

I ended up fixing this by extending Scroller with this code:

public class FixedSpeedScroller extends Scroller {      private int mDuration = 5000;      public FixedSpeedScroller(Context context) {         super(context);     }      public FixedSpeedScroller(Context context, Interpolator interpolator) {         super(context, interpolator);     }      public FixedSpeedScroller(Context context, Interpolator interpolator, boolean flywheel) {         super(context, interpolator, flywheel);     }       @Override     public void startScroll(int startX, int startY, int dx, int dy, int duration) {         // Ignore received duration, use fixed one instead         super.startScroll(startX, startY, dx, dy, mDuration);     }      @Override     public void startScroll(int startX, int startY, int dx, int dy) {         // Ignore received duration, use fixed one instead         super.startScroll(startX, startY, dx, dy, mDuration);     } } 

And using it like this:

try {     Field mScroller;     mScroller = ViewPager.class.getDeclaredField("mScroller");     mScroller.setAccessible(true);      FixedSpeedScroller scroller = new FixedSpeedScroller(mPager.getContext(), sInterpolator);     // scroller.setFixedDuration(5000);     mScroller.set(mPager, scroller); } catch (NoSuchFieldException e) { } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } 

I've basically hardcoded the duration to 5 seconds and made my ViewPager use it.

Hope this helps.

like image 131
marmor Avatar answered Sep 18 '22 09:09

marmor


I've wanted to do myself and have achieved a solution (using reflection, however). It's similar to the accepted solution but uses the same interpolator and only changes the duration based on a factor. You need to use a ViewPagerCustomDuration in your XML instead of ViewPager, and then you can do this:

ViewPagerCustomDuration vp = (ViewPagerCustomDuration) findViewById(R.id.myPager); vp.setScrollDurationFactor(2); // make the animation twice as slow 

ViewPagerCustomDuration.java:

import android.content.Context; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.view.animation.Interpolator;  import java.lang.reflect.Field;  public class ViewPagerCustomDuration extends ViewPager {      public ViewPagerCustomDuration(Context context) {         super(context);         postInitViewPager();     }      public ViewPagerCustomDuration(Context context, AttributeSet attrs) {         super(context, attrs);         postInitViewPager();     }      private ScrollerCustomDuration mScroller = null;      /**      * Override the Scroller instance with our own class so we can change the      * duration      */     private void postInitViewPager() {         try {             Class<?> viewpager = ViewPager.class;             Field scroller = viewpager.getDeclaredField("mScroller");             scroller.setAccessible(true);             Field interpolator = viewpager.getDeclaredField("sInterpolator");             interpolator.setAccessible(true);              mScroller = new ScrollerCustomDuration(getContext(),                     (Interpolator) interpolator.get(null));             scroller.set(this, mScroller);         } catch (Exception e) {         }     }      /**      * Set the factor by which the duration will change      */     public void setScrollDurationFactor(double scrollFactor) {         mScroller.setScrollDurationFactor(scrollFactor);     }  } 

ScrollerCustomDuration.java:

import android.annotation.SuppressLint; import android.content.Context; import android.view.animation.Interpolator; import android.widget.Scroller;  public class ScrollerCustomDuration extends Scroller {      private double mScrollFactor = 1;      public ScrollerCustomDuration(Context context) {         super(context);     }      public ScrollerCustomDuration(Context context, Interpolator interpolator) {         super(context, interpolator);     }      @SuppressLint("NewApi")     public ScrollerCustomDuration(Context context, Interpolator interpolator, boolean flywheel) {         super(context, interpolator, flywheel);     }      /**      * Set the factor by which the duration will change      */     public void setScrollDurationFactor(double scrollFactor) {         mScrollFactor = scrollFactor;     }      @Override     public void startScroll(int startX, int startY, int dx, int dy, int duration) {         super.startScroll(startX, startY, dx, dy, (int) (duration * mScrollFactor));     }  } 

Hope this helps someone!

like image 38
Oleg Vaskevich Avatar answered Sep 17 '22 09:09

Oleg Vaskevich