自定义循环滑动的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)。
直接上代码
1package com.vane.widget.cycleviewpager;
2 3import android.content.Context;
4import android.database.DataSetObserver;
5import android.support.v4.view.PagerAdapter;
6import android.support.v4.view.ViewPager;
7import android.util.AttributeSet;
8import android.view.View;
9import android.view.ViewGroup;
10 11publicclass CycleViewPager extends ViewPager {
12 13private InnerPagerAdapter mAdapter;
14 15public CycleViewPager(Context context) {
16super( context);
17 setOnPageChangeListener( null);
18 }
19 20public CycleViewPager(Context context, AttributeSet attrs) {
21super( context, attrs);
22 setOnPageChangeListener( null);
23 }
24 25 @Override
26publicvoid setAdapter(PagerAdapter arg0) {
27 mAdapter = new InnerPagerAdapter( arg0);
28super.setAdapter( mAdapter);
29 setCurrentItem( 1);
30 }
31 32 @Override
33publicvoid setOnPageChangeListener(OnPageChangeListener listener) {
34super.setOnPageChangeListener( new InnerOnPageChangeListener( listener));
35 }
36 37privateclass InnerOnPageChangeListener implements OnPageChangeListener {
38 39private OnPageChangeListener listener;
40privateint position;
41 42public InnerOnPageChangeListener(OnPageChangeListener listener) {
43this.listener = listener;
44 }
45 46 @Override
47publicvoid onPageScrollStateChanged(int arg0) {
48if(null != listener) {
49 listener.onPageScrollStateChanged( arg0);
50 }
51if(arg0 == ViewPager.SCROLL_STATE_IDLE) {
52if(position == mAdapter.getCount() - 1) {
53 setCurrentItem( 1, false);
54 }
55elseif(position == 0) {
56 setCurrentItem( mAdapter.getCount() - 2, false);
57 }
58 }
59 }
60 61 @Override
62publicvoid onPageScrolled(int arg0, float arg1, int arg2) {
63if(null != listener) {
64 listener.onPageScrolled( arg0, arg1, arg2);
65 }
66 }
67 68 @Override
69publicvoid onPageSelected(int arg0) {
70 position = arg0;
71if(null != listener) {
72 listener.onPageSelected( arg0);
73 }
74 }
75 }
76 77privateclass InnerPagerAdapter extends PagerAdapter {
78 79private PagerAdapter adapter;
80 81public InnerPagerAdapter(PagerAdapter adapter) {
82this.adapter = adapter;
83 adapter.registerDataSetObserver( new DataSetObserver() {
84 85 @Override
86publicvoid onChanged() {
87 notifyDataSetChanged();
88 }
89 90 @Override
91publicvoid onInvalidated() {
92 notifyDataSetChanged();
93 }
94 95 });
96 }
97 98 @Override
99publicint getCount() {
100return adapter.getCount() + 2;
101 }
102103 @Override
104publicboolean isViewFromObject(View arg0, Object arg1) {
105return adapter.isViewFromObject( arg0, arg1);
106 }
107108 @Override
109public Object instantiateItem(ViewGroup container, int position) {
110if(position == 0) {
111 position = adapter.getCount() - 1;
112 }
113elseif(position == adapter.getCount() + 1) {
114 position = 0;
115 }
116else {
117 position -= 1;
118 }
119return adapter.instantiateItem( container, position);
120 }
121122 @Override
123publicvoid destroyItem(ViewGroup container, int position, Object object) {
124 adapter.destroyItem( container, position, object);
125 }
126127 }
128 }
如何使用
使用方法和viewPager是一样一样的,你就认为是viewpager来使用就可以了。源码你可以在github上取https://github.com/vanezkw/cycleviewpager.git
总结
源码中大家也都看到了没有什么特别的其实就是平时讲的设计模式。之前提到的方式A个人认为并不完全是面向对象的方式,这个当然也看大家如何理解。
浙公网安备 33010602011771号