需求
无限增加的ViewPager在Android开发中没有无限循环的ViewPager常见,一般也就是日历这种情况。
效果图
初始数据只有一个0,向右翻页可以无限增长。
InfiniteViewPager操作效果.gif
思路
基本思路跟大多数先驱的做法差不多。
- 将PagerAdapter的getCount方法返回值为一个较大的数字,这里我返回了int类型的最大值,即Integer.MAX_VALUE;
- 初始item设置为Integer.MAX_VALUE的一半,即Integer.MAX_VALUE / 2;
- PagerAdapter的instantiateItem执行时根据position和数据列表计算出当前position应当显示的数据,先从数据列表里取对应数据,如果有,就返回给ViewHolder,如果没有,就从OnNeedAddDataCallback里获取;
- 每一个Item的数据和View都绑定在ViewHolder的实体内;
- 封装一个ViewHolderCreator,ViewHolder的回收、获取和更新都由ViewHolderCreator控制。
关于ViewHolderCreator
InfiniteViewPager工作流程 (1).png上图所示
当setOffscreenPageLimit方法设置limit为2,即左右预加载数各为2,从ViewHolderCreator中获取5个空闲的ViewHolder,加载初始数据。当向右翻一页时,回收最左边的ViewHolder,放入空闲的ViewHolder队列中,获取一个空闲的ViewHolder放入右边,填充数据。
使用方法
在XML中配置或者直接new一个都可以
<com.riverlet.riverletviewpager.InfiniteViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="300dp" />
InfiniteViewPager viewpager = view.findViewById(R.id.viewpager);
或者
InfiniteViewPager viewpager = new InfiniteViewPager(getContext());
给LoopViewPager设置数据和ViewHolderCreator
viewpager.setData(dataList, new InfiniteViewPager.ViewHolderCreator() {
@Override
public InfiniteViewPager.ViewHolder create() {
TextView textView = new TextView(getContext());
textView.setBackgroundColor(0xff199dff);
textView.setTextColor(Color.WHITE);
textView.setTextSize(50);
textView.setGravity(Gravity.CENTER);
textView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
return new InfiniteViewHolder(textView);
}
});
实现OnNeedAddDataCallback
viewpager.setOnNeedAddDataCallback(new InfiniteViewPager.OnNeedAddDataCallback<Integer>() {
// 添加数据在数据列表最前
@Override
public Integer addFirst(int position, Integer integer) {
return integer - 1;
}
//添加数据在数据列表最后
@Override
public Integer addLast(int position, Integer integer) {
return integer + 1;
}
});
方法介绍
/**
* 设置基础数据和ViewHolderCreator
*
* @param dataList 数据列表
* @param viewHolderCreator
*/
public void setData(List dataList, @NonNull ViewHolderCreator viewHolderCreator) ;
/**
* 获取当前显示Item的ViewHolder,即可获取当前显示的数据和View
*
* @return
*/
public ViewHolder getCurrentItemViewHolder();
/**
* 根据Item位置获取它的ViewHolder
*
* @param position
* @return
*/
public ViewHolder getViewHolderOfPosition(int position);
/**
* 跳转到指定Data的位置
*
* @param data
*/
public void setCurrentItemOfData(Object data);
/**
* 跳转到指定Data的位置
*
* @param data
* @param smoothScroll 是否带滚动动画
*/
public void setCurrentItemOfData(Object data, boolean smoothScroll);
/**
* 翻到下一页
*/
public void nextPage();
/**
* 翻到上一页
*/
public void lastPage();
/**
* 设置当前页变化的监听
* @param onCurrentPageChangeListener
*/
public void setOnCurrentPageChangeListener(OnCurrentPageChangeListener onCurrentPageChangeListener);
/**
* 获取数据Map
* @return
*/
public Map<Integer, Object> getDataMap();
/**
* 设置新增数据的回调
* @param onNeedAddDataCallback
*/
public void setOnNeedAddDataCallback(OnNeedAddDataCallback onNeedAddDataCallback);
注意
- 无限增加不是真的无限增加,总页数为Integer.MAX_VALUE,即2147483647,比较大,初始设置在中间位置;
- 虽然总页数为2147483647,但实际加载的页数只有5个(当前显示页以及左右个两个);
- 因为实际加载页数只有5个,所以setCurrentItem跳转到其他未加载的页数时,会出现bug,
所以在InfiniteViewPager里面setCurrentItem被阻断了,封装了setCurrentItemOfData作为跳转方法。
源码及Demo安装包
源码:ViewPagerDemo
Demo安装包:app-debug.apk
使用实力:自定义日历--RCalendarView
引申
无限循环的ViewPager:LoopViewPager
网友评论