内容简介:给自己的忠告:虽然轮子很好用,但是使用轮子的前提是:如果不去封装一些复杂的功能,自己会用最基本的方法写一个,不然再好的轮子那也是别人的,当自己项目遇到和轮子不一样的地方,那就只能束手无策或者改人家的源码,当然能看懂轮子的封装思想自己学以致用并且能够很轻松的更改源码那是最好不过的了。(1)采用Adapter内的getCount()方法返回Integer.MAX_VALUE。(2)在列表的最前面插入最后一条数据,在列表末尾插入第一个数据,造成循环的假象
给自己的忠告:虽然轮子很好用,但是使用轮子的前提是:如果不去封装一些复杂的功能,自己会用最基本的方法写一个,不然再好的轮子那也是别人的,当自己项目遇到和轮子不一样的地方,那就只能束手无策或者改人家的源码,当然能看懂轮子的封装思想自己学以致用并且能够很轻松的更改源码那是最好不过的了。
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
//当前选中页 private int currentPosition; //数据项个数 private List<Integer> itemList; //设置当前选中的item currentPosition = getStartItem(); viewPager1.setCurrentItem(currentPosition1); private int getStartItem() { // 我们设置当前选中的位置为Integer.MAX_VALUE / 2,这样开始就能往左滑动 // 但是要保证这个值与getRealPosition 的 余数为0,因为要从第一页开始显示 int currentItem = Integer.MAX_VALUE / 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 Integer.MAX_VALUE; } 复制代码
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() { @Override public 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.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() { @Override public void onPageScrolled(int i, float v, int i1) { } @Override public void onPageSelected(int i) { currentPosition2 = i; } @Override public 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() { @Override public void run() { if (mIsAutoPlay) { //方案二:多添两条数据 currentPosition2 = viewPager2.getCurrentItem(); currentPosition2++; if (currentPosition2 == bannerAdapter2.getCount() - 1) { //滑到最后一个 currentPosition2 = 1; //此处与上面不同 viewPager2.setCurrentItem(currentPosition2, false); mHandler2.postDelayed(this, mDelayedTime); } else if(currentPosition2==0){ //滑到第0个 currentPosition2 = bannerAdapter2.getCount() - 2; //此处与上面不同 viewPager2.setCurrentItem(currentPosition2, false); mHandler2.postDelayed(this, mDelayedTime); } else { 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,这样就没有了切换动画,导致生硬,所以不用这个。
本来没想实现方案二(想着会一种方法就行),但好奇心使我想看下到底有多生硬,然而我手动滑的时候并没有发现什么不一样,当我加入轮播滚动后才发现不同。
以下我一共放了四张图,当滑动第四张,再次循环放第一张图的时候,第二种方案就没有滑动的效果,直接切换了图片,而不是将图片滑动切换过来。大家可以仔细看下效果:
以上所述就是小编给大家介绍的《ViewPager两种方式实现无限轮播》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。