继承ViewPager实现自动滚动的例子已经很多了,不过有时候我们不想使用继承,比如一个类已经继承了ViewPager,或者不想更改过去的代码.
这里提供一个使用外部类的方法实现ViewPager自动翻页功能.直接上代码:
package lx.af.utils.ViewUtils;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import java.util.concurrent.TimeUnit;
/**
* author: lx
* date: 15-12-15
*
* helper to make ViewPager auto scroll
*/
public class ViewPagerAutoFlipper implements
ViewPager.OnPageChangeListener {
private static final long DEFAULT_FLIP_INTERVAL = TimeUnit.SECONDS.toMillis(3);
private ViewPager mViewPager;
private boolean mAutoFlip = false;
private long mFlipInterval = DEFAULT_FLIP_INTERVAL;
private long mLastFlipTime;
private int mScrollState = ViewPager.SCROLL_STATE_IDLE;
private int mPosition;
public static ViewPagerAutoFlipper newInstance(ViewPager pager) {
return new ViewPagerAutoFlipper(pager);
}
public ViewPagerAutoFlipper(ViewPager pager) {
mViewPager = pager;
mViewPager.addOnPageChangeListener(this);
mPosition = mViewPager.getCurrentItem();
}
/**
* @param interval auto flip interval, in millis
*/
public ViewPagerAutoFlipper setInterval(long interval) {
if (interval > 0) {
mFlipInterval = interval;
} else {
throw new IllegalArgumentException("interval should be positive");
}
return this;
}
/**
* @return true if ViewPager is auto flipping; false otherwise
*/
public boolean isAutoFlip() {
return mAutoFlip;
}
/**
* start ViewPager auto flip
*/
public void start() {
if (mViewPager != null) {
mAutoFlip = true;
mViewPager.removeCallbacks(mFlipRunnable);
mViewPager.postDelayed(mFlipRunnable, mFlipInterval);
}
}
/**
* stop ViewPager auto flip.
* should always call this in Activity.onDestroy to release handler callbacks,
* or mem leak may occur.
*/
public void stop() {
mAutoFlip = false;
if (mViewPager != null) {
mViewPager.removeCallbacks(mFlipRunnable);
}
}
/**
* reset to init state.
* should be called after {@link ViewPager#setAdapter(PagerAdapter)}
*/
public void reset() {
if (mViewPager != null) {
mViewPager.removeCallbacks(mFlipRunnable);
mViewPager.removeOnPageChangeListener(this);
mViewPager.addOnPageChangeListener(this);
mPosition = mViewPager.getCurrentItem();
mLastFlipTime = 0;
mScrollState = ViewPager.SCROLL_STATE_IDLE;
mViewPager.postDelayed(mFlipRunnable, mFlipInterval);
}
}
@Override
public void onPageSelected(int position) {
mPosition = position;
mLastFlipTime = System.currentTimeMillis();
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageScrollStateChanged(int state) {
mScrollState = state;
}
private boolean canAutoFlip() {
if (mViewPager == null || mViewPager.getAdapter() == null) {
return false;
}
long interval = System.currentTimeMillis() - mLastFlipTime;
if (interval < mFlipInterval - 300) {
// postDelayed() is not so accurate about delay time,
// we minus 300 to avoid post too soon caused by the deviation
mViewPager.removeCallbacks(mFlipRunnable);
mViewPager.postDelayed(mFlipRunnable, mFlipInterval - interval);
return false;
}
return mAutoFlip && mScrollState == ViewPager.SCROLL_STATE_IDLE;
}
private Runnable mFlipRunnable = new Runnable() {
@Override
public void run() {
if (mViewPager == null) {
// unlikely
return;
}
if (mViewPager.getWindowToken() == null) {
// window token no longer valid, exit loop
mViewPager.removeCallbacks(mFlipRunnable);
mViewPager.removeOnPageChangeListener(ViewPagerAutoFlipper.this);
return;
}
if (canAutoFlip()) {
int count = mViewPager.getAdapter().getCount();
int next = (mPosition + 1 == count) ? 0 : mPosition + 1;
mViewPager.setCurrentItem(next);
}
if (mAutoFlip) {
mViewPager.removeCallbacks(mFlipRunnable);
mViewPager.postDelayed(mFlipRunnable, mFlipInterval);
}
}
};
}
使用也很简单:
ViewPagerAutoFlipper.newInstance(mViewPager).setInterval(2000).start();
或者
// setAdapter 后调用 flipper.start()
mViewPager.setAdapter(mAdapter);
ViewPagerAutoFlipper flipper = new ViewPagerAutoFlipper(mViewPager);
flipper.setInterval(3000);
flipper.start();
...
flipper.stop();
...
// 重新 setAdapter 后需要调用 reset()
mViewPager.setAdapter(mAdapter);
flipper.reset();
代码很简单,主要的问题是判断如何退出 Runnable + postDelayed() 的循环.如果ViewPager不可用了还没有退出的话,就会造成当前Activity泄露.
一开始是在Activity的onDestroy()方法中显式调用flipper.stop(),后来觉得这样做太不优雅了,改为判断window token是否可用.
目前自测是可以的,不知是否有其他问题.
代码收录在我的Android App框架中:
https://github.com/liuxu0703/AppFrame/blob/master/appframe/src/main/java/lx/af/utils/ViewUtils/ViewPagerAutoFlipper.java
水平有限,有问题请指正~.