android 打造真正的无限循环viewpager

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/anyfive/article/details/52525262


转发请注明出处:http://blog.csdn.net/anyfive/article/details/52525262

前言

目前,无限循环的viewpager有两种实现方式:
1. 使adapter的getCount()返回Integer.MAX_VALUE,再在初始化时设置当前页面为第几百几千页(如:ViewPager.setCurrentItem(100*data.size));
2. 通过监听viewpager的滑动来设置页面。如当前有数据123,则设置页面为31231,当页面滑动到第一个3时,设置当前页面为第二个3,那么左右都可以滑动,当其滑动到第二个1时同理。

我们的实现方法

上述第一种实现方法网上已经有很多教程,大家可以自行去网上搜索,这里就不再重复。

我们要采用的是第二种实现方法,看到这里,有些试过的同学估计就要说了:『这个我早就试过了,当滑动到第一页和最后一页的时候会出现跳动的现象,太不友好了,博主真是XX』大兄弟你先别急,既然我知道这个问题,那么必定是解决了这个不友好的问题才写这篇博客的。

先来看看效果


首先,我们还是先来介绍一下这个思路给没有了解过的同学。

其实这个思路很简单:
1. 添加最后一条数据到第一条,添加第一条数据到最后一条;
2. 设置监听器;
3. 设置初始化时设置当前页面为第二页

我们知道使用这个思路会出现一个问题,就是:当滑动到第一页和最后一页时,会出现不友好的跳转。那么出现这个问题的原因是什么呢?通过在onPageSelected(int position)函数中打印log信息,我们发现这个函数在viewpager滑动动画还没结束的时候就已经被调用了,所以在这里调用setCurrentItem方法会强制取消当前正在进行的动画并跳转。

那么相应的,我们可以想到解决方法:
1. 在onPageSelected(int position)方法中记录被选中的页面;
2. 在onPageScrollStateChanged(int state)判断当前动画是否结束,当动画结束时调用setCurrentItem方法跳转页面。

是不是很简单?

一个适配器搞定,我们直接来看下代码:

public abstract class LoopVPAdapter<T> extends PagerAdapter implements ViewPager.OnPageChangeListener{

//    当前页面
    private int currentPosition = 0;

    protected Context mContext;
    protected ArrayList<View> views;
    protected ViewPager mViewPager;

    public LoopVPAdapter(Context context, ArrayList<T> datas, ViewPager viewPager) {
        mContext = context;
        views = new ArrayList<>();
//        如果数据大于一条
        if(datas.size() > 1) {
//            添加最后一页到第一页
            datas.add(0,datas.get(datas.size()-1));
//            添加第一页(经过上行的添加已经是第二页了)到最后一页
            datas.add(datas.get(1));
        }
        for (T data:datas) {
            views.add(getItemView(data));
        }
        mViewPager = viewPager;
        viewPager.setAdapter(this);
        viewPager.addOnPageChangeListener(this);
        viewPager.setCurrentItem(1,false);
    }

    @Override
    public int getCount() {
        return views.size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        container.addView(views.get(position));
        return views.get(position);
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView(views.get(position));
    }

    protected abstract View getItemView(T data);

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    }

    @Override
    public void onPageSelected(int position) {
        currentPosition = position;
    }

    @Override
    public void onPageScrollStateChanged(int state) {
//        若viewpager滑动未停止,直接返回
        if (state != ViewPager.SCROLL_STATE_IDLE) return;
//        若当前为第一张,设置页面为倒数第二张
        if (currentPosition == 0) {
            mViewPager.setCurrentItem(views.size()-2,false);
        } else if (currentPosition == views.size()-1) {
//        若当前为倒数第一张,设置页面为第二张
            mViewPager.setCurrentItem(1,false);
        }
    }


}

可以看到,我们将这个适配器写成抽象类,当你需要使用的时候,只需要继承这个类,并实现getItemView方法,就可以直接使用啦~~是不是很方便?

  • 在构造函数中,判断当数据大于一条时,添加第一页和最后一页,设置监听器,设置当前页面为第二页(即实际中的第一页)。
  • 在onPageSelected(int position)方法中记录当前页面,在onPageScrollStateChanged(int state)方法中跳转页面。

关键代码:

    @Override
    public void onPageSelected(int position) {
        currentPosition = position;
    }

    @Override
    public void onPageScrollStateChanged(int state) {
//        若viewpager滑动未停止,直接返回
        if (state != ViewPager.SCROLL_STATE_IDLE) return;
//        若当前为第一张,设置页面为倒数第二张
        if (currentPosition == 0) {
            mViewPager.setCurrentItem(imageViews.size()-2,false);
        } else if (currentPosition == imageViews.size()-1) {
//        若当前为倒数第一张,设置页面为第二张
            mViewPager.setCurrentItem(1,false);
        }
    }

使用

首先,继承这个适配器:

public class ImgAdapter extends LoopVPAdapter<String> {

    public ImgAdapter(Context context, ArrayList<String> datas, ViewPager viewPager) {
        super(context, datas, viewPager);
    }

    private ViewGroup.LayoutParams layoutParams;

    @Override
    protected View getItemView(String data) {
        if (layoutParams == null) {
            layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        }
        ImageView imageView = new ImageView(mContext);
        imageView.setLayoutParams(layoutParams);
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        ImageUtils.loadImage(mContext, data, imageView);
        return imageView;
    }


}

然后,直接使用:

vp = (ViewPager) findViewById(R.id.vp);

urls.add("http://seopic.699pic.com/photo/00005/5186.jpg_wh1200.jpg");
urls.add("http://seopic.699pic.com/photo/50010/0719.jpg_wh1200.jpg");
urls.add("http://seopic.699pic.com/photo/50009/9449.jpg_wh1200.jpg");
urls.add("http://seopic.699pic.com/photo/50002/5923.jpg_wh1200.jpg");
urls.add("http://seopic.699pic.com/photo/50001/9330.jpg_wh1200.jpg");
urls.add("http://seopic.699pic.com/photo/50009/9191.jpg_wh1200.jpg");

loopVPAdapter = new ImgAdapter(this,urls,vp);

使用方法比较简单,这里就不再累赘了。


源码地址:https://github.com/whichname/LoopViewPager

猜你喜欢

转载自blog.csdn.net/anyfive/article/details/52525262