Change Viewpager Animation Duration When Sliding Programmatically

Change ViewPager animation duration when sliding programmatically

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));
}
}

Increase viewpager smoothscroll duration

Can you modify this part of the code and insert a Log statement?

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));
Log.d("TAG", "mScroller is: " + mScroller + ", "
+ mScroller.getClass().getSuperclass().getCanonicalName() + "; this class is "
+ this + ", " + getClass().getSuperclass().getCanonicalName());
scroller.set(this, mScroller);
} catch (Exception e) {
Log.e("MyPager", e.getMessage());
}

And then post the output?

EDIT: The issue is the import statements are not correct. mScroller is a android.widget.Scroller and you cannot assign to it a com.WazaBe.HoloEverywhere.widget.Scroller.

Slowing speed of Viewpager controller in android

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.

ViewPager2 - Slider transition sliding too fast

I have encountered a similar problem when working with ViewPager2. I had two items in my ViewPager, and put the switch to the next item as the action of a button. The first time you press it, the animation is instantaneous, like you describe. However, in my setup, if you press again on it, it scrolls back to the left. Once it does that, the animation works correctly (both left and right).

From what I can tell from your code, in your case you continue to scroll in a single direction - hence you only observe the instantaneous scrolling. Try to play around with it and make it scroll back, instead of only forward. See if the animation appears correctly in that case.

EDIT: If you find that the same behavior applies in your case as well, you can apply a completely inelegant hack:

You can "browse" through your ViewPager's items when you're opening up your activity, as quickly as possible. Then, after going through each item, switch back to the first item and then just apply whatever logic you have now. If you do this, the items will already be "loaded" and the animations will work.

Of course, while you're doing that in the "background", you can display a progress loader when you first get into the activity, and once you've scrolled back to the first item, display your activity. The user will think the activity is "loading", but in reality you will be going through each of your ViewPager's items, effectively "pre-loading" them.

Completely ugly solution, but it should work. I hope someone can come up with a better one than this, as I don't exactly know the reason why the animation isn't playing correctly the first time.

How to switch automatically between viewPager pages

You can use Timer for this purpose. The following code is self explanatory:

// ---------------------------------------------------------------------------

Timer timer;
int page = 1;

public void pageSwitcher(int seconds) {
timer = new Timer(); // At this line a new Thread will be created
timer.scheduleAtFixedRate(new RemindTask(), 0, seconds * 1000); // delay
// in
// milliseconds
}

// this is an inner class...
class RemindTask extends TimerTask {

@Override
public void run() {

// As the TimerTask run on a seprate thread from UI thread we have
// to call runOnUiThread to do work on UI thread.
runOnUiThread(new Runnable() {
public void run() {

if (page > 4) { // In my case the number of pages are 5
timer.cancel();
// Showing a toast for just testing purpose
Toast.makeText(getApplicationContext(), "Timer stoped",
Toast.LENGTH_LONG).show();
} else {
mViewPager.setCurrentItem(page++);
}
}
});

}
}

// ---------------------------------------------------------------------------

Note 1: Make sure that you call pageSwitcher method after setting up adapter to the viewPager properly inside onCreate method of your activity.

Note 2: The viewPager will swipe every time you launch it. You have to handle it so that it swipes through all pages only once (when the user is viewing the viewPager first time)

Note 3: If you further want to slow the scrolling speed of the viewPager, you can follow this answer on StackOverflow.


Tell me in the comments if that could not help you...



Related Topics



Leave a reply



Submit