在android中,使用過viewpager的人都清楚,我們如果使用viewpager進行滑動時,如果通過手指滑動來進行的話,可以根據手指滑動的距離來實現,但是如果通過setCurrentItem函數來實現的話,則會發現沒有過度動畫的效果,而是直接閃過去的,那么在有時我們就會遇到一個需求,比如說我們想要通過使用setCurrentItem函數來進行viewpager的滑動,並且需要有過度滑動的動畫,那么,該如何做呢?首先我們大致看下viewpager的源代碼:
首先我們看下setCurrentItem的執行了什么?

我們繼續往下看setCurrentItemInternal的函數,

繼續往下看setCurrentItemInternal的函數內容,

看到這個一大坨代碼后是不是有點慌,別怕,我們其實看到這個函數就夠了scrollToItem,然后我們看這個函數具體執行的是:

這個函數中,其實我們最主要關心的也是smoothScrollTo函數就好了,我們具體看下這個函數,


然后這個函數中,其實我們看到具體執行滑動的其實就一句話,就是mScroller.startScroll(sx, sy, dx, dy, duration);
那么我們可以看到,是mScroller這個對象進行滑動的,那么,最簡單粗暴的方法就是重寫這個類,並且重寫后怎么付給viewpager呢,這就是接下來講的,這其中用到了java的反射機制,我們來看下:
public class FixedSpeedScroller extends Scroller {
private int mDuration = 1500;
public FixedSpeedScroller(Context context) {
super(context);
}
public FixedSpeedScroller(Context context, Interpolator interpolator) {
super(context, interpolator);
}
@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);
}
public void setmDuration(int time) {
mDuration = time;
}
public int getmDuration() {
return mDuration;
}
}
這是我們重寫的scroller的類,其實比較簡單,我們只是將原來滑動的方法進行修改,滑動的具體時間,改為我們自己設定的,傳入的參數作廢即可。這樣的話,我們通過自己自定義滑動的時間,就可以控制滑動的速度。然后下一步就是如何將其賦值給原先的viewpager類,這里呢,就用到了java的反射的機制,我們看具體的代碼:
try {
Field field = ViewPager.class.getDeclaredField("mScroller");
field.setAccessible(true);
FixedSpeedScroller scroller = new FixedSpeedScroller(mViewPager.getContext(),
new AccelerateInterpolator());
field.set(mViewPager, scroller);
scroller.setmDuration(2000);
} catch (Exception e) {
}
這呢,就是通過反射的機制,將我們自定義的scroller傳進去,從而實現了我們自己控制滑動速度。
