首页 > 代码库 > 自定义循环滑动的viewpager

自定义循环滑动的viewpager

摘要

今天和大家分享一下如何定制一个可以循环滑动的viewpager。其实今天更重要的提供一种组件化思想,当然你可以理解为面向对象思想。

吐槽一下网上流行的实现方式吧(为了方便说明,下文称之为方式A),方式A是重写adapter的getCount方法,返回一个很大的数(值为max),adapter中的getView方法中的position重新根据实际数量取模,把viewpager设置在max二分之一的位置。因为这个值很大所以基本不可能滑动到position=0或者position=max的位置,不过确切来说这并不是无限循环,采用脚本之类的应该可以滑动到边界(没有试验过)。

 

我们的需求

快速把之前viewpager相关的代码改成无限循环。

这个需求很简单就是在已有的代码上完成无限循环。当然你可以根据方式A来完成,它是通过适配器来完成无限循环的,不过这种方式你需要改的代码并不少,毕竟你得改适配器。

本文需要提供的方式B就登场了,好处在于不用改你的adapter,只需要把你的viewpager改成本文中的组件CycleViewPager就可以了,其他的都不用改。

 

原理

CycleViewPager继承ViewPager。当向右翻页(文中指的向右翻页是指手指由右向左滑,向左翻页反之),数据滑动到最后一条数据时调用setCurrentItem(0)返回第一条,当向左翻页,数据滑动到第一条数据时setCurrentItem(getCount()-1)返回到最后一条数据。在设置数据的时候需要多生成两条数据,比如原始数据是[a,b,c,d,e],那么生成的数据为[e,a,b,c,d,e,a],原始数据第一条前面加了最后一条数据e,原始数据的最后一条的后面加了原始数据的第一条数据a。从a滑到e时,继续向右翻页那么就到了数据a(最右边的那个a),停止滑动时调用setCurrentItem(1)返回第一条数据a(最左边的那个a);从e滑动到a时,继续向左翻页那么就到了数据e(做左边的那个e),停止滑动时调用setCurrentItem(5)。

 

直接上代码

  1 package com.vane.widget.cycleviewpager;  2   3 import android.content.Context;  4 import android.database.DataSetObserver;  5 import android.support.v4.view.PagerAdapter;  6 import android.support.v4.view.ViewPager;  7 import android.util.AttributeSet;  8 import android.view.View;  9 import android.view.ViewGroup; 10  11 public class CycleViewPager extends ViewPager { 12  13     private InnerPagerAdapter mAdapter; 14  15     public CycleViewPager(Context context) { 16         super( context); 17         setOnPageChangeListener( null); 18     } 19  20     public CycleViewPager(Context context, AttributeSet attrs) { 21         super( context, attrs); 22         setOnPageChangeListener( null); 23     } 24  25     @Override 26     public void setAdapter(PagerAdapter arg0) { 27         mAdapter = new InnerPagerAdapter( arg0); 28         super.setAdapter( mAdapter); 29         setCurrentItem( 1); 30     } 31  32     @Override 33     public void setOnPageChangeListener(OnPageChangeListener listener) { 34         super.setOnPageChangeListener( new InnerOnPageChangeListener( listener)); 35     } 36  37     private class InnerOnPageChangeListener implements OnPageChangeListener { 38  39         private OnPageChangeListener listener; 40         private int position; 41  42         public InnerOnPageChangeListener(OnPageChangeListener listener) { 43             this.listener = listener; 44         } 45  46         @Override 47         public void onPageScrollStateChanged(int arg0) { 48             if(null != listener) { 49                 listener.onPageScrollStateChanged( arg0); 50             } 51             if(arg0 == ViewPager.SCROLL_STATE_IDLE) { 52                 if(position == mAdapter.getCount() - 1) { 53                     setCurrentItem( 1, false); 54                 } 55                 else if(position == 0) { 56                     setCurrentItem( mAdapter.getCount() - 2, false); 57                 } 58             } 59         } 60  61         @Override 62         public void onPageScrolled(int arg0, float arg1, int arg2) { 63             if(null != listener) { 64                 listener.onPageScrolled( arg0, arg1, arg2); 65             } 66         } 67  68         @Override 69         public void onPageSelected(int arg0) { 70             position = arg0; 71             if(null != listener) { 72                 listener.onPageSelected( arg0); 73             } 74         } 75     } 76  77     private class InnerPagerAdapter extends PagerAdapter { 78  79         private PagerAdapter adapter; 80  81         public InnerPagerAdapter(PagerAdapter adapter) { 82             this.adapter = adapter; 83             adapter.registerDataSetObserver( new DataSetObserver() { 84  85                 @Override 86                 public void onChanged() { 87                     notifyDataSetChanged(); 88                 } 89  90                 @Override 91                 public void onInvalidated() { 92                     notifyDataSetChanged(); 93                 } 94  95             }); 96         } 97  98         @Override 99         public int getCount() {100             return adapter.getCount() + 2;101         }102 103         @Override104         public boolean isViewFromObject(View arg0, Object arg1) {105             return adapter.isViewFromObject( arg0, arg1);106         }107 108         @Override109         public Object instantiateItem(ViewGroup container, int position) {110             if(position == 0) {111                 position = adapter.getCount() - 1;112             }113             else if(position == adapter.getCount() + 1) {114                 position = 0;115             }116             else {117                 position -= 1;118             }119             return adapter.instantiateItem( container, position);120         }121 122         @Override123         public void destroyItem(ViewGroup container, int position, Object object) {124             adapter.destroyItem( container, position, object);125         }126 127     }128 }

 

如何使用

使用方法和viewPager是一样一样的,你就认为是viewpager来使用就可以了。源码你可以在github上取https://github.com/vanezkw/cycleviewpager.git

 

总结

源码中大家也都看到了没有什么特别的其实就是平时讲的设计模式。之前提到的方式A个人认为并不完全是面向对象的方式,这个当然也看大家如何理解。

如果文中有任何疑问或者不妥之处欢迎留言交流。在此也留下QQ群311536202,欢迎交流。

 

自定义循环滑动的viewpager