无限滚动ViewPager的实现
Andorid 默认提供的 ViewPager 是不可以循环滚动的, 当滑动到边界时就不能滚动了. 但是实现 Banner 时, 体验最好的还是无限滚动, 为此需要自定义 ViewPager 来实现无限滚动.
PagerAdapter部分:
首先为了实现无限滚动,
getCount()
需要返回一个很大的数, 比如Integer.MAX_VALUE
.为了节省内存, 默认ViewPager只缓存前后1个Page, 就内存中只有perIndex, currentIndex, nextIndex 三个 View , 实际上也发现只需要三个 View 就可以实现无限滚动.
instantiateItem()
方法中, 需要注意的就是获取到 position 对应的 View 后, 如果view.getParent()
是 container 时, 需要先从 container 中移除该 View , 否则会导致 View 重复添加到 parent 报错.@Override public Object instantiateItem(ViewGroup container, int position) { //mView保存了3个View,用于实现轮播. //mView[position % 3]即获取该position对应的View View view = mViews[position % 3]; if (container.equals(view.getParent())) { //防止添加到同一个parent container.removeView(view); } container.addView(view); }
重写
destroyItem()
方法, 什么都不操作, 不调用super方法. 这里之所以自己管理 View 的添加和移除, 是因为源码中是先调用instantiateItem
添加再调用destroyItem
移除的, 如果用它的方法, 3个 View 的时候重复添加 parent 就会 crash.isViewFromObject()
方法正常重写即可.@Override public boolean isViewFromObject(View view, Object object) { return view == object; }
ViewPager部分:
默认 ViewPager 的 Scroller 滑动时间是250ms, 轮播时滑动太快了,所以需要反射 Scroller 来设置合理的滑动时间:
public class MyScroller extends Scroller { //默认1秒 private int mDuration = 1000; public MyScroller(Context context) { this(context, null); } public MyScroller(Context context, Interpolator interpolator) { super(context, interpolator); } @Override public void startScroll(int startX, int startY, int dx, int dy, int duration) { // Ignore received duration, use fixed one instead super.startScroll(startX, startY, dx, dy, mDuration); } @Override public void startScroll(int startX, int startY, int dx, int dy) { // Ignore received duration, use fixed one instead super.startScroll(startX, startY, dx, dy, mDuration); } } //调用以下方法设置 public void setViewPagerScrollTime() { try { Field mScroller = ViewPager.class.getDeclaredField("mScroller"); mScroller.setAccessible(true); MyScroller scroller = new MyScroller(getContext()); mScroller.set(this, scroller); } catch (Exception e) { e.printStackTrace(); } }
注意 ViewPager 的 offset 设为1.
`mViewPager.setOffscreenPageLimit(1);`
在设置 Adapter 或更新数据后, 记得设置 ViewPager 到中间页, 否则往左滑动就会到边界.
//数据大小为size. int mid = Integer.MAX_VALUE / 2 - ((Integer.MAX_VALUE / 2) % size); holder.mViewPager.setCurrentItem(mid, false);