给自己的忠告:虽然轮子很好用,但是使用轮子的前提是:如果不去封装一些复杂的功能,自己会用最基本的方法写一个,不然再好的轮子那也是别人的,当自己项目遇到和轮子不一样的地方,那就只能束手无策或者改人家的源码,当然能看懂轮子的封装思想自己学以致用并且能够很轻松的更改源码那是最好不过的了。

1. 实现思路

两种方案:

(1)采用Adapter内的getCount()方法返回Integer.MAX_VALUE。

(2)在列表的最前面插入最后一条数据,在列表末尾插入第一个数据,造成循环的假象

2. 具体实现

2.1 方案一:getCount()返回Integer.MAX_VALUE

2.1.1 ViewPager无限循环

在ViewPager的Adapter内的getCount方法中,返回一个很大的数Integer.MAX_VALUE,理论上可以无限滑动。当显示完一个真实列表的周期后,又从真实列表的0位置显示数据,造成无限循环轮播的假象。因为ViewPager第一页不能向左滑动循环,所以我们要通过mViewPager.setCurrentItem(Integer.MAX_VALUE/2)设置选中的位置,这样最开始就可以向左滑动,但是因为要显示第一页所以该值%数据个数==0。因为设置为Integer.MAX_VALUE后会在setCurrentItem()的时候发生ANR,所以这里使用一个自定义的较大的数比较好,这里我是用500

//当前选中页
private int currentPosition;
//数据项个数
private List<Integer> itemList;public static final int mLooperCount = 500;//设置当前选中的item
currentPosition = getStartItem();
viewPager1.setCurrentItem(currentPosition1);private int getStartItem() {if(getRealCount() == 0){return 0;}// 我们设置当前选中的位置为Integer.MAX_VALUE / 2,这样开始就能往左滑动// 但是要保证这个值与getRealPosition 的 余数为0,因为要从第一页开始显示int currentItem = getRealCount() * BannerAdapter.mLooperCount / 2;if(currentItem % getRealCount()  ==0 ){return currentItem;}// 直到找到从0开始的位置while (currentItem % getRealCount() != 0){currentItem++;}return currentItem;
}//获取数据项个数
private int getRealCount() {return itemList == null ? 0 : itemList.size();
}
复制代码

Adapter只需将getCount()返回Integer.MAX_VALUE即可(这里我们改为具体的数值),其他的操作是正常的操作。

@Override
public int getCount() {return getRealCount() * mLooperCount;
}
复制代码

2.1.2 加入轮播功能

采用Handler的postDelayed方法

private Handler mHandler = new Handler();@Override
protected void onResume() {super.onResume();//开始轮播mHandler.postDelayed(mLoopRunnable, mDelayedTime);
}@Override
protected void onPause() {super.onPause();//停止轮播mHandler.removeCallbacks(mLoopRunnable);
}
复制代码
private final Runnable mLoopRunnable = new Runnable() {@Overridepublic void run() {if (mIsAutoPlay) {//方案一currentPosition1 = viewPager1.getCurrentItem();currentPosition1++;if (currentPosition1 == bannerAdapter.getCount() - 1) {      //滑到最后一个时currentPosition1 = 0;                               //切换到第0个viewPager1.setCurrentItem(currentPosition1, false);mHandler.postDelayed(this, mDelayedTime);} else {viewPager1.setCurrentItem(currentPosition1);mHandler.postDelayed(this, mDelayedTime);}            } else {mHandler.postDelayed(this, mDelayedTime);}}
};
复制代码

2.1.3 使用Integer.MAX_VALUE的争议

有人会觉得会影响内存,大家可以参考这篇文章Android ViewPager 无限轮播Integer.MAX_VALUE 争议(看源码)就能够解决疑惑。

2.1.4 注意

使用Integer.MAX_VALUE会在setCurrentItem()的时候发生ANR,所以还是设置为一个比较大的数比较好。在代码中我已经更改为返回getRealCount()*500这一数值,如果文章中有返回Integer.MAX_VALUE的,那就是我还没更正,大家请自行更改。

2.2 方案二:数据项首尾添加两条数据

2.2.1 ViewPager无限循环

假设有三条数据,分别编号1、2、3,我们再创建一个新的列表,长度为真实列表的长度+2,在最前面插入最后一条数据3,在最后面插入第一条数据1,新列表就变为3、1、2、3、1,当viewpager滑动到位置0时就通过setCurrentItem(int item,boolean smoothScroll)方法将页面切换到位置3,同理当滑动到位置4时,通过该方法将页面切换到位置1,这样给我们的感觉就是无限循环。

private int currentPosition2;
private void initData2() {itemList2 = new ArrayList<>();itemList2.add(R.drawable.ic_pic4);itemList2.add(R.drawable.ic_pic1);itemList2.add(R.drawable.ic_pic2);itemList2.add(R.drawable.ic_pic3);itemList2.add(R.drawable.ic_pic4);itemList2.add(R.drawable.ic_pic1);bannerAdapter2 = new BannerAdapter2(itemList2);viewPager2.setAdapter(bannerAdapter2);currentPosition2 = 1;viewPager2.setCurrentItem(currentPosition2);viewPager2.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {@Overridepublic void onPageScrolled(int i, float v, int i1) {}@Overridepublic void onPageSelected(int i) {currentPosition2 = i;}@Overridepublic void onPageScrollStateChanged(int state) {//验证当前的滑动是否结束if (state == ViewPager.SCROLL_STATE_IDLE) {if (currentPosition2 == 0) {viewPager2.setCurrentItem(itemList2.size() - 2, false);//切换,不要动画效果} else if (currentPosition2 == itemList2.size() - 1) {viewPager2.setCurrentItem(1, false);//切换,不要动画效果}}}});
}
复制代码

2.2.2 加入轮播功能

private Handler mHandler2 = new Handler();
@Override
protected void onResume() {super.onResume();//开始轮播mHandler2.postDelayed(mLoopRunnable2, mDelayedTime);
}@Override
protected void onPause() {super.onPause();//停止轮播mHandler2.removeCallbacks(mLoopRunnable2);
}
复制代码
private final Runnable mLoopRunnable2 = new Runnable() {@Overridepublic void run() {if (mIsAutoPlay) {//方案二:多添两条数据currentPosition2 = viewPager2.getCurrentItem();currentPosition2++;//不需要为了循环轮播来判断是否到达最后一页,在监听器中已经为我们做了此操作viewPager2.setCurrentItem(currentPosition2);mHandler2.postDelayed(this, mDelayedTime);} else {mHandler2.postDelayed(this, mDelayedTime);}}
};
复制代码

与方案一不同的地方就是当滑动到最后一个时,切换到下标为1的页面,当滑动下标为0的页面时,切换到最后一个

2.3 比较

依然范特稀西 在文章中这样说到:第二种方案在切换动画的时候,因为当滑到位置4时,我们通过setCurrentItem(int item,boolean smoothScroll)方法,来将其切换到位置1才有了无限循环的效果,但为了不被发现,第二个参数smoothScroll设置为false,这样就没有了切换动画,导致生硬,所以不用这个。

本来没想实现方案二(想着会一种方法就行),但好奇心使我想看下到底有多生硬,但没有发现生硬的效果。因为我们在onPageScrollStateChanged()方法里监听了动画结束的状态,所以当滑动到第四张,再次开启一个周期的时候,我们其实是滑动到了第五张,就是我们往尾部添加的那张图片,此时是有动画的,并不是itemlist下标为0的位置,而且在此监听器中,当判断其实最后一张的时候,我们已经通过setCurrentItem()不带动画效果的方式偷偷的把它切换到下标为1的位置了,所以在handler通过currentItem++方式再次滑动时,它滑动到的是下标为2的图片,也是带效果的,所以不存在什么生硬的效果。 以下我一共放了四张图,大家可以仔细看下效果:

3. 总结

以上就是最基本的方法来实现ViewPager的无限轮播的全部内容。具体代码见Github。

其实我们常见的Banner图还有Indicator指示器(就是底部的小点),这个我用的其实还是依然范特稀西自定义的Indicator,因为确实很好用,而且封装的话也很简单,虽然一样的,但是我还是想下一篇再记录一下封装的过程,让自己加深下印象,下篇文章见。

4. 参考文章

Android ViewPager 无限轮播Integer.MAX_VALUE 争议(看源码)

ViewPager系列之 仿魅族应用的广告BannerView

Android 使用ViewPager实现无限轮播出现空白bug原因及解决方案(Integer.MAX_VALUE实现方式)

转载于:https://juejin.im/post/5d08b8a251882559ed71d789

ViewPager两种方式实现无限轮播相关推荐

  1. iOS无限轮播图片的两种方式

    2019独角兽企业重金招聘Python工程师标准>>> 1 使用UIScrollview实现无限轮播原理 在开发中常需要对广告或者是一些图片进行自动的轮播,也就是所谓的无限滚动. 在 ...

  2. iOS 两种不同的图片无限轮播

    代码地址如下: http://www.demodashi.com/demo/11608.html 前记 其实想写这个关于无限轮播的记录已经很久很久了,只是没什么时间,这只是一个借口,正如:时间就像海绵 ...

  3. 无限轮播图 三种实现方式

    无限轮播图三种实现方式:(源码地址) 1.首尾相接方式: https://github.com/jakajacky/DRScrollerView 2.imageView复用方式: https://gi ...

  4. android viewpager无限轮播

    概述 github地址:https://github.com/Double2hao/ViewPagerCycleTest 一直很好奇ViewPager无限轮播的实现方式,于是稍微研究了下,作此文记录之 ...

  5. iOS换一种思路写一个无限轮播的滚动视图

    换一种思路写一个无限轮播的滚动视图 写这篇博客已经距离我当时写差不多有一个月时间了,也完善了很多,基本是没有bug的,如果有,不妨留言,喜欢的话,劳烦各位点个赞,不喜欢的,不妨看看思路,提提意见 1. ...

  6. php 递归实现无限极分类和排序_无限极分类的两种方式,递归和引用

    说到无限极分类,比较常见的做法是在建表的时候,增加一个parnet_id字段用来区别自己所属的分类(是顶级分类还是子分类) 由于展示数据的时候,需要表达出这种所属关系,所以必然要在读取数据的时候进行一 ...

  7. XLisetView+ViewPager无限轮播+多条目加载

    导xlistview jar包 权限 //主布局 <?xml version="1.0" encoding="utf-8"?> <Linear ...

  8. android ViewPager实现无限轮播和设置监听事件

    ViewPager的无限轮播,主要以实现为主.代码如下 首先定义activity_viewpager.xml: <LinearLayout android:layout_width=" ...

  9. ViewPager无限轮播与小点点

    在Android开发中经常简单会用到 ViewPager无限轮播与小点点,下面就简单介绍一下,其中的小点点可以找美工绘制,Android工程师也可以自己手动简易制作 定义XML布局文件 <Rel ...

最新文章

  1. Java B2B2C多用户商城 springcloud架构- common-service 项目构建过程(七)...
  2. python ctypes库5_如何传递一个字符串数组
  3. ESP8266--学习笔记(八)串口源码分析
  4. perl--模块安装方法和常用模块
  5. 拆分路径 java_JAVA 类文件中的路径如何拆分和替换
  6. 1-5 三整数排序(算法竞赛入门经典)
  7. ES6学习笔记(三):教你用js面向对象思维来实现 tab栏增删改查功能
  8. 数组删除一行_一行Python代码能做出哪些神器的事情
  9. 高性能数据库集群:读写分离
  10. Java多线程笔记(一):JMM与基础关键字
  11. 1124 Raffle for Weibo Followers(20 分)
  12. Git教程(快速上手,超详细)
  13. 微信音频通话数据保存服务器,微信语音通话怎么录MP3音频文件
  14. Excel表格宏命令教学一:VBA入门
  15. 数据泵并行parallel参数问题
  16. java cipher用法_Java使用Cipher类实现加密的过程详解
  17. 最全的Office 2003图标集合
  18. 翻译Deep Learning and the Game of Go(3)第2章:围棋是一个机器学习难题(规则部分就不翻了)
  19. php ios接口,关于ios 调用php接口
  20. JDK1.8 api 中文文档下载

热门文章

  1. 小程序渲染html的两种方法
  2. 参数--argumengs
  3. LINUN 网络连接小记
  4. Gartner:2013-2014年全球MSS市场分析
  5. gbk编码的简介以及针对gbk文本飘红截断原理以及实现
  6. ubuntu无线网络开关
  7. 新建网站与新建Asp.Net+Web+应用程序的区别
  8. 好朋友简简单单,好情谊清清爽爽,好缘份久久长长
  9. Spring Boot CMI 使用笔记
  10. Eclipse配置工程自动执行ant实现热部署