ViewPager 实现无线循环
ViewPager 无限循环作为Banner来使用是一个很常见的场景,那么它的实现原理是怎么样的呢?相信这一块大家已经都比较熟悉了。话不多说,先上图。
其中所有的黑色框用来展示原始的数据集合,为了实现无限循环的效果,这里有一个小把戏,就是在首部添加了一个原始数据集合最后的元素,同时,将原始集合第一个元素添加到了尾部,这样,就重新组成了一个新的数据集合。
/**
* 数据源
*/
private List mDataList;
/**
* 真实 视图 集合
*/
private List mViews;
private ViewPager mViewPager;
/**
* 记录 ViewPager 当前的位置
*/
private int mCurrentPosition;
public BaseBannerAdapter(Context pContext, List pDataList, ViewPager pViewPager) {
mContext = pContext;
mDataList = pDataList;
mViewPager = pViewPager;
if (pDataList != null) {
mViews = new LinkedList<>();
if (mDataList.size() > 1) {
mDataList.add(0, mDataList.get(mDataList.size() - 1));
mDataList.add(mDataList.get(1));
...
...
...
}
}
mViewPager.addOnPageChangeListener(this);
}
@Override
public void onPageScrollStateChanged(int state) {
// 多于1,才会循环跳转
if (mViews.size() > 1) {
// 如果当前是在首位,那么跳转到倒数第2位
if (mCurrentPosition == 0) {
mViewPager.setCurrentItem(mViews.size() - 2, false);
// 如果当前是在末位,跳转到第2位
} else if (mCurrentPosition == mViews.size() - 1) {
mViewPager.setCurrentItem(1, false);
}
}
}
@Override
public void onPageSelected(int position) {
mCurrentPosition = position;
}
判断集合对象,如果原始集合size大于1,就要考虑无限循环了。
在首部和尾部添加对应的集合元素
为 ViewPager 注册
onPageChangeListener
监听器,并实现相关方法在
onPageSelected
方法中记录当前页面的位置,同时,在onPageScrollStateChanged
方法中设置页面的切换
到这里,ViewPager 的无限循环逻辑就已经结束了。是不是很简单?
下面我们把这个 PagerAdapter 做成一个通用的 Adapter
- 声明抽象类
- 声明抽象方法
public abstract View getView(T t, int pPosition);
为了正确的传递数据实体 t 和 数据索引 pPosition,我们还需要做一下处理。
public BaseBannerAdapter(Context pContext, List pDataList, ViewPager pViewPager) {
...
if (mDataList.size() > 1) {
mDataList.add(0, mDataList.get(mDataList.size() - 1));
mDataList.add(mDataList.get(1));
int index = 0;
// 用户感知到的集合数量
int size = pDataList.size() - 2;
for (T t : pDataList) {
View view;
if (index % size == 0) {
view = getView(t, size);
} else if (index % size == 1) {
view = getView(t, 1);
} else {
view = getView(t, index);
}
mViews.add(view);
index++;
}
}
}
...
}
上面的代码,将 getView 交给子类去实现,让用户根据业务需求去个性化渲染 View。
到此,ViewPager 的无限循环就全部说完了。下面贴上完整的代码。
import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.View;
import android.view.ViewGroup;
import java.util.LinkedList;
import java.util.List;
/**
* 自定义 BaseBannerAdapter 抽象基类
*
* @author Shelly
* @date 2018/02/01
*/
public abstract class BaseBannerAdapter extends PagerAdapter implements ViewPager.OnPageChangeListener {
private Context mContext;
/**
* 数据源
*/
private List mDataList;
/**
* 真实 视图 集合
*/
private List mViews;
private ViewPager mViewPager;
/**
* 记录 ViewPager 当前的位置
*/
private int mCurrentPosition;
public BaseBannerAdapter(Context pContext, List pDataList, ViewPager pViewPager) {
mContext = pContext;
mDataList = pDataList;
mViewPager = pViewPager;
if (pDataList != null) {
mViews = new LinkedList<>();
if (mDataList.size() > 1) {
mDataList.add(0, mDataList.get(mDataList.size() - 1));
mDataList.add(mDataList.get(1));
int index = 0;
// 用户感知到的集合数量
int size = pDataList.size() - 2;
for (T t : pDataList) {
View view;
if (index % size == 0) {
view = getView(t, size);
} else if (index % size == 1) {
view = getView(t, 1);
} else {
view = getView(t, index);
}
mViews.add(view);
index++;
}
}
}
mViewPager.addOnPageChangeListener(this);
}
public Context getContext() {
return mContext;
}
public List getDataList() {
return mDataList;
}
/**
* 实现自己 View 渲染的逻辑业务
*
* @param t
* @param pPosition
* @return
*/
public abstract View getView(T t, int pPosition);
@Override
public void onPageScrollStateChanged(int state) {
// 多于1,才会循环跳转
if (mViews.size() > 1) {
// 如果当前是在首位,那么跳转到倒数第2位
if (mCurrentPosition == 0) {
mViewPager.setCurrentItem(mViews.size() - 2, false);
// 如果当前是在末位,跳转到第2位
} else if (mCurrentPosition == mViews.size() - 1) {
mViewPager.setCurrentItem(1, false);
}
}
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
mCurrentPosition = position;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view = mViews.get(position);
container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(mViews.get(position));
}
@Override
public int getCount() {
return mViews.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
}