6

I'm using a ViewPager subclass MyPager (which is almost the same), and I use its setCurrentItem(int index, boolean smooth) method, with the smooth parameter set to true. It's actually a little smoother than with parameter set to 'false', but I'd like to increase the animation duration to make the transition more visible.

I have gathered some information from different posts and this solution looks perfect. I've ended up with this code"

MyPager.java :

public class MyPager extends ViewPager {
    public MyPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.enabled = true;
        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) {
            Log.e("MyPager", e.getMessage());
        }
    }

    /**
     * Set the factor by which the duration will change
     */
    public void setScrollDurationFactor(double scrollFactor) {
        mScroller.setScrollDurationFactor(scrollFactor);
    }
}

ScrollerCustomDuration.java

public class ScrollerCustomDuration extends Scroller {
    private double mScrollFactor = 2;

    public ScrollerCustomDuration(Context context) {
        super(context);
    }

    public ScrollerCustomDuration(Context context, Interpolator interpolator) {
        super(context, interpolator);
    }

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

}

The thing is, I can't get rid of this exception, when running through the line scroller.set(this, mScroller); of MyPager :

java.lang.IllegalArgumentException: invalid value for field

Any idea?

Community
  • 1
  • 1
elgui
  • 3,303
  • 4
  • 28
  • 37
  • mScroller = new ScrollerCustomDuration(getContext(), (Interpolator) interpolator.get(null)); Why did you put interpolator.get(null) ? – Tsunaze Jan 08 '13 at 14:12
  • well, actually I didn't, but that's in the post I'm refering to... what do you suggest ? – elgui Jan 08 '13 at 14:35
  • btw, I have the same exception when I replace with " mScroller = new ScrollerCustomDuration(getContext(), new DecelerateInterpolator());" – elgui Jan 08 '13 at 14:42
  • Could you edit and post the `import` statements in your code? – Oleg Vaskevich Jan 08 '13 at 16:03
  • NVM, just see my answer; also you use `interpolator.get(null)` because `interpolator` is static and doesn't belong to an instance. – Oleg Vaskevich Jan 08 '13 at 16:11
  • try this, its simpler and worked for me. http://stackoverflow.com/a/14776244/2054956 – tegbird Feb 08 '13 at 16:42

1 Answers1

7

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.

Oleg Vaskevich
  • 12,444
  • 6
  • 63
  • 80
  • here it is : mScroller is: com.myproject.components.ScrollerCustomDuration@416ce8f8, com.WazaBe.HoloEverywhere.widget.Scroller; this class is com.myproject.components.MyPager@416c7550, android.support.v4.view.ViewPager – elgui Jan 08 '13 at 18:36
  • 1
    Ah, this is the problem. You are importing the wrong `Scroller`. Make sure you have `import android.widget.Scroller;`. Not `com.WazaBe.HoloEverywhere.widget.Scroller`. – Oleg Vaskevich Jan 08 '13 at 20:40
  • it works, thanks so much ! I let you edit your answer or post a new one so I can validate it =) – elgui Jan 08 '13 at 21:23
  • Np, glad you got it working! Auto import isn't always right :) – Oleg Vaskevich Jan 09 '13 at 00:28
  • 4
    If you are using proguard don't forget to add this line: -keep class android.support.v4.** {*;} otherwise you'll get null pointer when getDeclaredField() – GuilhE Oct 31 '14 at 18:35