Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change ViewPager animation duration when sliding programmatically

I'm changing slide with the following code:

viewPager.setCurrentItem(index++, true); 

But it changes too fast. Is there a way to set manually the animation speed?

like image 594
User Avatar asked May 30 '12 07:05

User


2 Answers

I've wanted to do myself and have achieved a solution (using reflection, however). I haven't tested it yet but it should work or need minimal modification. Tested on Galaxy Nexus JB 4.2.1. 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 {             Field scroller = ViewPager.class.getDeclaredField("mScroller");             scroller.setAccessible(true);             Field interpolator = ViewPager.class.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 129
Oleg Vaskevich Avatar answered Oct 13 '22 00:10

Oleg Vaskevich


I have found better solution, based on @df778899's answer and the Android ValueAnimator API. It works fine without reflection and is very flexible. Also there is no need for making custom ViewPager and putting it into android.support.v4.view package. Here is an example:

private void animatePagerTransition(final boolean forward) {      ValueAnimator animator = ValueAnimator.ofInt(0, viewPager.getWidth());     animator.addListener(new Animator.AnimatorListener() {         @Override         public void onAnimationStart(Animator animation) {         }          @Override         public void onAnimationEnd(Animator animation) {             viewPager.endFakeDrag();         }          @Override         public void onAnimationCancel(Animator animation) {             viewPager.endFakeDrag();         }          @Override         public void onAnimationRepeat(Animator animation) {         }     });      animator.setInterpolator(new AccelerateInterpolator());     animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {          private int oldDragPosition = 0;          @Override         public void onAnimationUpdate(ValueAnimator animation) {             int dragPosition = (Integer) animation.getAnimatedValue();             int dragOffset = dragPosition - oldDragPosition;             oldDragPosition = dragPosition;             viewPager.fakeDragBy(dragOffset * (forward ? -1 : 1));         }     });      animator.setDuration(AppConstants.PAGER_TRANSITION_DURATION_MS);     if (viewPager.beginFakeDrag()) {         animator.start();     } } 

UPDATE:

Just checked if this solution can be used to swipe several pages at once (for example if first page should be showed after the last one). This is slightly modified code to handle specified page count:

private int oldDragPosition = 0;  private void animatePagerTransition(final boolean forward, int pageCount) {     // if previous animation have not finished we can get exception     if (pagerAnimation != null) {         pagerAnimation.cancel();     }     pagerAnimation = getPagerTransitionAnimation(forward, pageCount);     if (viewPager.beginFakeDrag()) {    // checking that started drag correctly         pagerAnimation.start();     } }  private Animator getPagerTransitionAnimation(final boolean forward, int pageCount) {     ValueAnimator animator = ValueAnimator.ofInt(0, viewPager.getWidth() - 1);     animator.addListener(new Animator.AnimatorListener() {         @Override         public void onAnimationStart(Animator animation) {         }          @Override         public void onAnimationEnd(Animator animation) {             viewPager.endFakeDrag();         }          @Override         public void onAnimationCancel(Animator animation) {             viewPager.endFakeDrag();         }          @Override         public void onAnimationRepeat(Animator animation) {             viewPager.endFakeDrag();             oldDragPosition = 0;             viewPager.beginFakeDrag();         }     });      animator.setInterpolator(new AccelerateInterpolator());     animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {          @Override         public void onAnimationUpdate(ValueAnimator animation) {             int dragPosition = (Integer) animation.getAnimatedValue();             int dragOffset = dragPosition - oldDragPosition;             oldDragPosition = dragPosition;             viewPager.fakeDragBy(dragOffset * (forward ? -1 : 1));         }     });      animator.setDuration(AppConstants.PAGER_TRANSITION_DURATION_MS / pageCount); // remove divider if you want to make each transition have the same speed as single page transition     animator.setRepeatCount(pageCount);      return animator; } 
like image 25
lobzik Avatar answered Oct 12 '22 22:10

lobzik