問題
大家都知道 ViewPager 可以通過 mViewPager.setCurrentItem(index, true) 來始切換動(dòng)畫時(shí)進(jìn)行平緩的滑動(dòng)余耽,但是如果我們的需求是控制滑動(dòng)時(shí)間的話,會(huì)發(fā)現(xiàn) ViewPager 好像并沒有提供這一個(gè)方法技健。我們可以查看ViewPager 的源碼:
public void setCurrentItem(int item, boolean smoothScroll) {
mPopulatePending = false;
setCurrentItemInternal(item, smoothScroll, false);
}
發(fā)現(xiàn) setCurrentItem 走的是一個(gè) setCurrentItemInternal(item, smoothScroll, false) 方法
void setCurrentItemInternal(int item, boolean smoothScroll, boolean always) {
setCurrentItemInternal(item, smoothScroll, always, 0);
}
而這個(gè)方法所調(diào)用的 void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) 方法貌似是可以指定速度的勒葱,但是先別高興的太早浪汪,這個(gè)方法居然不是 public 的。凛虽。也就是說我們調(diào)用不了死遭。但是這也難不倒我們,用反射就輕松解決了凯旋。 有興趣你可以用反射調(diào)用這個(gè)方法試試看呀潭,反正我是試過了,速度好像并沒有什么明顯的變化瓦阐,再仔細(xì)看了看源碼蜗侈,我們發(fā)現(xiàn)最終走的 smoothScrollTo 方法中有一句
duration = Math.min(duration, MAX_SETTLE_DURATION)
然而我們發(fā)現(xiàn) ViewPager 中有一個(gè)常量 private static final int MAX_SETTLE_DURATION = 600; // ms
也就是說 duration 無論如何都不會(huì)超過 600ms 的,那我們偏要大于 600ms 呢睡蟋?
畢竟道高一尺魔高一丈踏幻,我們發(fā)現(xiàn)有了 duration 后,會(huì)調(diào)用 mScroller.startScroll(sx, sy, dx, dy, duration) 方法戳杀,終究還是要走 mScroller 的该面,那我們用反射修改 mScroller不就行了嗎夭苗?
效果前后展示
有沒有感覺太快了呢?
這樣是不是好一點(diǎn)了呢
解決方案
重寫一個(gè) Scroller 類:
/**
* 利用這個(gè)類來修正ViewPager的滑動(dòng)速度
* 我們重寫 startScroll方法隔缀,忽略傳過來的 duration 屬性
* 而是采用我們自己設(shè)置的時(shí)間
*/
public class FixedSpeedScroller extends Scroller {
public int mDuration=1500;
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) {
startScroll(startX,startY,dx,dy,mDuration);
}
@Override public void startScroll(int startX, int startY, int dx, int dy, int duration) {
//管你 ViewPager 傳來什么時(shí)間题造,我完全不鳥你
super.startScroll(startX, startY, dx, dy, mDuration);
}
public int getmDuration() {
return mDuration;
}
public void setmDuration(int duration) {
mDuration = duration;
}
}
利用反射把我們的 FixedSpeedScroller 類設(shè)置給 ViewPager
/**
* 通過反射來修改 ViewPager的mScroller屬性
*/
try {
Class clazz=Class.forName("android.support.v4.view.ViewPager");
Field f=clazz.getDeclaredField("mScroller");
FixedSpeedScroller fixedSpeedScroller=new FixedSpeedScroller(this,new LinearOutSlowInInterpolator());
fixedSpeedScroller.setmDuration(2000);
f.setAccessible(true);
f.set(mViewPager,fixedSpeedScroller);
} catch (Exception e) {
e.printStackTrace();
}
這個(gè)時(shí)候再設(shè)置 mViewPager.setCurrentItem(index, true) 的時(shí)候應(yīng)該就可以看到緩慢滑動(dòng)的效果了。