Android不继承ViewPager实现自动滚动翻页功能

继承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

水平有限,有问题请指正~.




你可能感兴趣的:(Android,App,android,viewpager)