viewpager的无限轮播有两种办法
一、Integer.MAX_VALUE
原理是将Adapter的getCount返回Integer.MAX_VALUE,然后让viewpager的初始位置定位到Integer.MAX_VALUE / 2 的位置,这样左右就各有十几亿的滑动空间,就实现了一个无限滑动的假象
(稍微优化一下,可以定位到数据源的第一个,Integer.MAX_VALUE / 2 - Integer.MAX_VALUE / 2 %
data.size())
直接上代码
public class ImageAdapter extends PagerAdapter {
private Context mContext;
private List<String> mUrls;
public ImageAdapter(Context context, List<String> urls){
mUrls = urls;
mContext = context;
}
@Override
public int getCount() {
return mUrls == null ? 0 : mUrls.size() < 2 ? mUrls.size() : Integer.MAX_VALUE;
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return view == object;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
ImageView view = new ImageView(mContext);
view.setScaleType(ImageView.ScaleType.CENTER_CROP);
Glide.with(mContext).load(mUrls.get(position % mUrls.size())).into(view);
container.addView(view);
return view;
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
container.removeView((View) object);
}
}
private ViewPager mVp;
private ImageAdapter mVpAdapter;
private void initVp() {
mVp = findViewById(R.id.vp);
mVpAdapter = new ImageAdapter(this,urls);
mVp.setAdapter(mVpAdapter);
// 在这里设置这么大的数字没有问题的原因是因为,这个时候处于Activity的onCreate,里面的UI还有没计算完毕,所有不会造成主线程卡顿
mVp.setCurrentItem(Integer.MAX_VALUE / 2 - Integer.MAX_VALUE / 2 % urls.size(),false);
}
虽然十几亿,但是理论上是滑的完的,这已经足够让程序员很不爽了,然后还有一个问题
定位到Integer的中间值之后一次跳跃超过viewpager的mOffscreenPageLimit之后会被阻塞主线程
mAaa.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 这里UI已经加载完毕,再去设置跨越很大的数字时,会阻塞主线程
if(mVp.getCurrentItem() == 0){
mVp.setCurrentItem(Integer.MAX_VALUE / 2 - Integer.MAX_VALUE / 2 % urls.size(),false);
}
else{
mVp.setCurrentItem(0,false);
}
}
});
具体原因不详述了,感兴趣可以做一下实验
二、增加数据源
增加数据源的原理
就是在前后加上数据,形成一个圆,然后接下来要做的事就是当滑动到第一个或者最后一个时来一个无缝切换
这种方式就需要默认选中第二个,也就是下标1,就可以看起来定位到了数据第一个位置
接下来上代码
public class Image2Adapter extends PagerAdapter {
private Context mContext;
private List<String> mUrls;
private List<String> mAdapterData = new ArrayList<>();
public Image2Adapter(Context context, List<String> urls){
mUrls = urls;
mContext = context;
dealAdapterData();
}
public List<String> getUrls(){
return mUrls;
}
private void dealAdapterData(){
mAdapterData.clear();
if(mUrls == null){
mUrls = new ArrayList<>();
}
mAdapterData.addAll(mUrls);
if(mAdapterData.size() > 0){
// 添加最后一个元素到第一个
mAdapterData.add(0,mUrls.get(mUrls.size() - 1));
// 添加第一个元素到最后一个
mAdapterData.add(mUrls.get(0));
}
}
@Override
public int getCount() {
return mAdapterData.size();
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return view == object;
}
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
ImageView view = new ImageView(mContext);
view.setScaleType(ImageView.ScaleType.CENTER_CROP);
Glide.with(mContext).load(mAdapterData.get(position)).into(view);
container.addView(view);
return view;
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
container.removeView((View) object);
}
}
private int mCurrentPagePosition = 0;
private ViewPager mVp;
private Image2Adapter mVpAdapter;
private void initVp() {
mVp = findViewById(R.id.vp);
mVp.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// 放在这里的想法是,当偏移量为零时,说明已经滑动完毕了,但是结果会闪屏一下,原因是虽然偏移量为零了,但是动画可能还未结束,这时候切换会终止动画导致闪屏
// if(positionOffset <= 0) {
// if (mCurrentPagePosition == 0) {
// mVp.setCurrentItem(mVpAdapter.getUrls().size(), false);
// } else if (mCurrentPagePosition == mVpAdapter.getCount() - 1) {
// mVp.setCurrentItem(1, false);
// }
// }
}
@Override
public void onPageSelected(int position) {
mCurrentPagePosition = position;
// 放在这里会因为动画未执行完就强制切换,视觉上有些生硬
// if (mCurrentPagePosition == 0) {
// mVp.setCurrentItem(mVpAdapter.getUrls().size(), false);
// } else if (mCurrentPagePosition == mVpAdapter.getCount() - 1) {
// mVp.setCurrentItem(1, false);
// }
}
@Override
public void onPageScrollStateChanged(int state) {
// 之所以放在这里是因为其他地方放着都有问题
if(state == ViewPager.SCROLL_STATE_IDLE){
if (mCurrentPagePosition == 0) {
mVp.setCurrentItem(mVpAdapter.getUrls().size(), false);
} else if (mCurrentPagePosition == mVpAdapter.getCount() - 1) {
mVp.setCurrentItem(1, false);
}
}
}
});
mVpAdapter = new Image2Adapter(this,urls);
mVp.setAdapter(mVpAdapter);
// 默认选中第二个数据,因为第一个数据是添加的最后一个
mVp.setCurrentItem(1);
}
这个解决了上面的滑动限制,以及阻塞主线程的问题,但是会有新问题,如果添加PageTransform就会有很奇怪的问题就不做详述了,目前我知道的解决办法是重新setAdapter()