自定義循環滑動的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         @Override
104         public boolean isViewFromObject(View arg0, Object arg1) {
105             return adapter.isViewFromObject( arg0, arg1);
106         }
107 
108         @Override
109         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         @Override
123         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,歡迎交流。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM