一行代码引入 ViewPager 无限循环 + 页码显示

(出处:https://cloud.tencent.com/developer/user/1148436/activities)

前序:

  网上的这类 ViewPager 很多,但是很多都不够好,体现在 bug多、对少页面不支持,例如1~2张图片、功能整合不全(无限+页码)等等,本类由我从零到无完成的,基本已找完 bug,注释丰富,方便大家理解。

特点:

  1,代码量少 , 共两个类,约合 310 行代码 (除去注释)

  2,可扩展 , 再加个 handler 即可实现自动轮播

  3,时间复杂度低

  4,耦合度低,只依赖了 imageLoader,可以自己切换

  5,关键点皆给出了详细注释,方便二次开发

功能:

  1,右滑无限循环(2^32,或更大),支持页面数>=2, 左滑循环直至原始第一张;

  2,上述效果伴随着正确的页面小点显示,具体效果可自定义

使用:

      // 第一个参数是 Activity;第二个是 ViewPager 对象;第三个是 imageLoader 实例,若使用自己的方法加载图片,请修改代码;第四个是图片链接字符串数组  

       new MyViewPager(this,viewpager,imageLoder,imageUrls) 

             .setUnClickLooper(true) // 设置开启第一种效果的无限循环

             .setClickLooper(true)    //  设置开启第二种效果的无限循环

             .init();                         //  实例化全部  

效果图:

  第一类效果,布局嵌套时,缩略图形式显示滑动

  第二类效果,点击单张图片进入 dialog 风格,大图显示形式

类简介:

  上述两种效果都能自己选择是否开启无限滑动。

  LoopViewpagerAdapter 类,继承于 PagerAdapter,主要实现功能是无限循环,逻辑处理比较集中于此,通过接口方式加载页 View。
  1 package cn.share.bananacloud.coustomViews.coustomEdittextInput.MyViewPager;
  2 
  3 import android.app.Activity;
  4 import android.support.v4.view.PagerAdapter;
  5 import android.util.Log;
  6 import android.view.LayoutInflater;
  7 import android.view.View;
  8 import android.view.ViewGroup;
  9 
 10 /**
 11  * Created by 林冠宏 on 2016/4/9.
 12  *
 13  * viewPager 无限循环
 14  *
 15  */
 16 
 17 public class LoopViewpagerAdapter extends PagerAdapter{
 18 
 19     private int images;
 20     private String[] imageUrls;
 21     private View[] views;
 22     private boolean isLooper;
 23     private LayoutInflater layoutInflater;
 24     private getItemViewListener getItemViewListener;
 25 
 26     public LoopViewpagerAdapter(
 27             Activity activity,
 28             String[] imageUrls,
 29             boolean isLooper, /** 是否进行无限循环 */
 30             getItemViewListener getItemViewListener)
 31     {
 32         this.isLooper = isLooper;
 33         this.images = imageUrls.length;
 34         this.layoutInflater = activity.getLayoutInflater();
 35         this.imageUrls = imageUrls;
 36         views = new View[images];
 37         this.getItemViewListener = getItemViewListener;
 38     }
 39 
 40     @Override
 41     public int getCount() {
 42         if(isLooper){
 43             if(images<3){ /** 1~2 张图片的情况 强制不开启循环 */
 44                 return images;
 45             }else {
 46                 return 65535; /** 设置足够大 2^32 */
 47             }
 48         }else{
 49             return images;
 50         }
 51     }
 52 
 53     /** 调用顺序 destroyItem -> instantiateItem */
 54 
 55     @Override
 56     public void destroyItem(ViewGroup container, int position, Object object) {
 57         Log.d("zzzzz","destroy "+position);
 58         container.removeView((View) object); /** 和 instantiateItem 相照应,这个是移除,不用担心内存会累加 */
 59     }
 60 
 61     @Override
 62     public Object instantiateItem(ViewGroup container,int position) {
 63         Log.d("zzzzz", "position " + position);
 64         if(isLooper && images==3){
 65             /** 3张的特殊处理,在先右滑了一定张数后,再左滑,此时初始化的 距离当前位置 的第前2张和后面一张会重复 (x-2) == (x+1) */
 66             View view = getItemViewListener.getItemView(layoutInflater, container, imageUrls[position%images], position);
 67             container.addView(view);
 68             return view;
 69         }else {
 70             if (position < images) {
 71                 if (views[position] == null) {
 72                     views[position] = getItemViewListener.getItemView(layoutInflater, container, imageUrls[position], position);
 73                 }
 74             } else if (position == images && isLooper) { /** 解决由 setCurrentItem 引发的问题 */
 75                 /** 时间复杂度不高,每经过一次,进入一次 */
 76                 /** 如果看大图vp 从临界最大值点击进来,此时没有之前的 view 赋值,直接 view[max-1] 会造成 空指针 exception,这是会初始化的有 max-2,max,max-1 */
 77                 /*if(images>2){ // 最小情况的判断,因为此时的 container 还没有移除下标 0 的图片,再添加的话会造成不能重复添加的异常
 78                     views[0] = getItemViewListener.getItemView(layoutInflater,container,imageUrls[0],0);
 79                 }else{ // 刚好是 2 张,手动移除下标 0
 80 
 81                 }*/
 82                 /** 如果 共4张图,此时 positon = 3 setCurrentItem() 就会造成加载了 4-2,4,4-1,4 在 view[] 是越界状态,故需要手动赋值 0,2和3 也初始化了,但是 1 没
 83                  *  若一直右滑,到 下标 1 便会抛 Cannot add a null child view to a ViewGroup,所以要 加上 views[images - 3] 也初始化
 84                  * */
 85                 views[0] = getItemViewListener.getItemView(layoutInflater, container, imageUrls[0], 0);
 86                 views[images - 3] = getItemViewListener.getItemView(layoutInflater, container, imageUrls[images - 3], 0);
 87                 container.addView(views[0]);  /** add 0 不会有问题, */
 88                 return views[0];
 89             }
 90         }
 91 
 92         container.addView(views[position%images]);
 93         return views[position%images];
 94     }
 95 
 96     @Override
 97     public boolean isViewFromObject(View view, Object o){
 98         return view.equals(o);
 99     }
100 
101     public interface getItemViewListener{
102         View getItemView(LayoutInflater layoutInflater,ViewGroup container,final String url,final int position);
103     }
104 
105 }
  MyViewPager 类,无父类,内部使用了 LoopViewpagerAdapter ,在无限循环的基础上,附加实现了页码小点的显示。
  1 package cn.share.bananacloud.coustomViews.coustomEdittextInput.MyViewPager;
  2 
  3 import android.app.Activity;
  4 import android.app.AlertDialog;
  5 import android.graphics.Bitmap;
  6 import android.support.v4.view.ViewPager;
  7 import android.util.Log;
  8 import android.view.LayoutInflater;
  9 import android.view.MotionEvent;
 10 import android.view.View;
 11 import android.view.ViewGroup;
 12 import android.view.Window;
 13 import android.widget.ImageView;
 14 import android.widget.LinearLayout;
 15 import android.widget.ProgressBar;
 16 import android.widget.TextView;
 17 
 18 import com.nostra13.universalimageloader.core.ImageLoader;
 19 import com.nostra13.universalimageloader.core.assist.FailReason;
 20 import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
 21 
 22 import cn.share.bananacloud.R;
 23 import cn.share.bananacloud.common.commonDataHelper;
 24 import cn.share.bananacloud.coustomViews.coustomEdittextInput.zoomImageView.PhotoView;
 25 import cn.share.bananacloud.tools.imageLoderHelper;
 26 
 27 /**
 28  * Created by 林冠宏 on 2016/4/9.
 29  *
 30  * viewPager 无限滑动 + 点击看大图,仍可滑动 + 当前张号页码
 31  *
 32  */
 33 
 34 public class MyViewPager {
 35 
 36     private Activity activity;
 37     private String[] imageUrls;
 38     protected ImageLoader imageLoder = null;
 39     private ViewPager viewPager;
 40     private int limitTemp = 0; /** 临界中间值 */
 41     private int picnum;
 42     private boolean unClickLooper = false;
 43     private boolean ClickLooper = false;
 44 
 45     public MyViewPager(
 46             Activity activity,
 47             ViewPager viewPager,
 48             ImageLoader imageLoder,
 49             String[] imageUrls
 50     ){
 51         this.activity = activity;
 52         this.imageUrls = imageUrls;
 53         this.imageLoder = imageLoder;
 54         this.viewPager = viewPager;
 55         picnum = imageUrls.length;
 56     }
 57 
 58     public MyViewPager setUnClickLooper(boolean unClickLooper){
 59         this.unClickLooper = unClickLooper;
 60         return this;
 61     }
 62 
 63     public MyViewPager setClickLooper(boolean ClickLooper){
 64         this.ClickLooper = ClickLooper;
 65         return this;
 66     }
 67 
 68     public void init(){
 69         viewPager.setAdapter
 70                 (
 71                         new LoopViewpagerAdapter
 72                                 (
 73                                         activity,
 74                                         imageUrls,
 75                                         unClickLooper,
 76                                         new LoopViewpagerAdapter.getItemViewListener() {
 77                                             @Override
 78                                             public View getItemView(LayoutInflater layoutInflater, ViewGroup container, final String url, final int position) {
 79                                                 View view = layoutInflater.inflate(R.layout.cy_item_main_image, container, false);
 80                                                 ImageView imageView = (ImageView) view.findViewById(R.id.image);
 81                                                 imageView.setOnClickListener(new View.OnClickListener() {
 82                                                     @Override
 83                                                     public void onClick(View v) {
 84                                                         int temp = position%picnum; /** 记得取余数 position 在无限循环的模式不是 0 ~ picnum */
 85                                                         if(temp==0 && position!=0){
 86                                                             showVPimage(picnum-1);
 87                                                         }else{
 88                                                             showVPimage(temp);
 89                                                         }
 90 
 91                                                     }
 92                                                 });
 93                                                 final ProgressBar spinner = (ProgressBar) view.findViewById(R.id.loading);
 94 
 95                                                 imageLoder.displayImage(url, imageView,
 96                                                         imageLoderHelper.getLoderOption(commonDataHelper.phoneWidth, R.drawable.hot_live_default_image, 0), new SimpleImageLoadingListener() {
 97                                                             @Override
 98                                                             public void onLoadingStarted(String imageUri, View view) {
 99                                                                 spinner.setVisibility(View.VISIBLE);
100                                                                 Log.d("zzzzz", "onLoadingStarted");
101                                                             }
102 
103                                                             @Override
104                                                             public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
105                                                                 spinner.setVisibility(View.GONE);
106                                                             }
107 
108                                                             @Override
109                                                             public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
110                                                                 Log.d("zzzzz", "onLoadingComplete "+imageUri);
111                                                                 spinner.setVisibility(View.GONE);
112                                                             }
113                                                         });
114                                                 return view;
115                                             }
116                                         }
117                                 )
118                 );
119 
120         viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
121             @Override
122             public void onPageScrolled(int i, float v, int i1) {
123 
124             }
125 
126             @Override
127             public void onPageSelected(int i) { /** 先于 instantiateItem 执行 */
128                 TextView nowCount = (TextView) activity.findViewById(R.id.nowCount);
129                 if((i+1)%picnum==0){
130                     nowCount.setText("" + picnum + " /");
131                 }else {
132                     nowCount.setText("" + (i + 1) % picnum + " /");
133                 }
134             }
135 
136             @Override
137             public void onPageScrollStateChanged(int i) {
138 
139             }
140         });
141     }
142 
143     private void showVPimage(int positon) {
144         final AlertDialog dlg = new AlertDialog.Builder(activity).create();
145 
146         View localView = LayoutInflater.from(activity).inflate(R.layout.viewpager, null);
147 
148         localView.setOnTouchListener(new View.OnTouchListener() {
149             @Override
150             public boolean onTouch(View v, MotionEvent event) {
151                 dlg.dismiss();
152                 return false;
153             }
154         });
155 
156         ViewPager viewPager = (ViewPager) localView.findViewById(R.id.imageContainer);
157         final LinearLayout pointContainer = (LinearLayout) localView.findViewById(R.id.pointContainer);
158         for(int i=0;i<picnum;i++){
159             ImageView imageView = (ImageView) LayoutInflater.from(activity).inflate(R.layout.viewpager_point,pointContainer,false);
160             pointContainer.addView(imageView);
161         }
162         viewPager.setAdapter
163                 (
164                         new LoopViewpagerAdapter
165                                 (
166                                         activity,
167                                         imageUrls,
168                                         ClickLooper,
169                                         new LoopViewpagerAdapter.getItemViewListener() {
170                                             @Override
171                                             public View getItemView(LayoutInflater layoutInflater, ViewGroup container, String url, int position) {
172                                                 View view = layoutInflater.inflate(R.layout.show_big_pic, container, false);
173                                                 PhotoView imageView = (PhotoView) view.findViewById(R.id.bigImage);
174                                                 imageView.setdimissDialog(new PhotoView.dimissDialog() {
175                                                     @Override
176                                                     public void doDimissDialog() {
177                                                         dlg.dismiss();
178                                                     }
179                                                 });
180                                                 try {
181                                                     imageLoder.displayImage
182                                                             (
183                                                                     url,
184                                                                     imageView,
185                                                                     imageLoderHelper.getLoderOption(commonDataHelper.phoneWidth+50, R.drawable.hot_live_default_image,0)
186                                                             );
187                                                 } catch (Exception ignored){}
188                                                 return view;
189                                             }
190                                         }
191                                 )
192                 );
193         viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
194             @Override
195             public void onPageScrolled(int i, float v, int i1) {
196 
197             }
198 
199             @Override
200             public void onPageSelected(int i) { /** 先于 instantiateItem 执行 */
201                 Log.d("onPageSelected","onPageSelected ->"+i);
202                 /** 为了减少 CPU 和 内存的 绘图消耗,这里不采用 for 等循环的方式改 点背景,改用条件语句 */
203                 if(ClickLooper){
204                     Log.d("onPageSelected","i is ->"+i +" limitTemp is "+limitTemp);
205                     /** 循环情况临界点的颜色恢复 */
206                     if((i % picnum)==(picnum-1) && limitTemp == 0){  /** 左滑 */
207                         ((ImageView) pointContainer.getChildAt(0)).setImageResource(R.drawable.white_point_xml);
208                     }else {
209                         if (i >= picnum && i % picnum == 0) { /** 右滑 */
210                             ((ImageView) pointContainer.getChildAt(picnum - 1)).setImageResource(R.drawable.white_point_xml);
211                         }
212                     }
213                 }
214                 i = i % picnum;
215                 ((ImageView) pointContainer.getChildAt(i)).setImageResource(R.drawable.color_point);
216                 if (i != 0 && i != picnum - 1) { /** 非临界值,两边都要修改 */
217                     ((ImageView) pointContainer.getChildAt(i>limitTemp ? i-1:i+1)).setImageResource(R.drawable.white_point_xml);
218                 }else {
219                     ((ImageView) pointContainer.getChildAt(i==picnum-1 ? i-1:i+1)).setImageResource(R.drawable.white_point_xml);
220                 }
221                 limitTemp = i;
222             }
223 
224             @Override
225             public void onPageScrollStateChanged(int i) {
226 
227             }
228         });
229         viewPager.setCurrentItem(positon);
230         ((ImageView)pointContainer.getChildAt(positon)).setImageResource(R.drawable.color_point);
231 
232 
233         Window localWindow = dlg.getWindow();
234         localWindow.getAttributes();
235         dlg.show();
236         localWindow.setContentView(localView);
237         localWindow.setGravity(17);
238         localWindow.setLayout(-1, -1);
239     }
240 
241 }

Demo项目 github 链接:

https://github.com/af913337456/lghLoopViewPager?files=1

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏向治洪

ViewPager 实现 Galler 效果, 中间大图显示,两边小图展示

正常情况下, ViewPager 一页只能显示一项数据, 但是我们常常看到网上,特别是电视机顶盒的首页经常出现中间大图显示两端也都露出一点来,这种效果怎么实现呢...

4845
来自专栏向治洪

关于ListView中包含EditText数据复用引起异常的解决方案

概述 前几天测试提了一个bug,在ListView中添加留言信息,导致错乱的问题。实际上就是ListView需要添加一个EditText,复用导致错乱的问题,这...

2009
来自专栏Android小菜鸡

巧妙运用补间动画,自定义广告轮播CarouselView 2.0

  这是前一篇文章绘制的CarouselView的升级版,有兴趣的同学,可以去关注一下笔者前一篇文章。自定义广告图片轮播View——CarouselView

682
来自专栏小巫技术博客

A022-列表容器之ExpandableListView

761
来自专栏五毛程序员

五毛的cocos2d-x学习笔记05-场景与场景动画,动作

1686
来自专栏Android开发指南

10. 面向holder编程、自动轮询

34712
来自专栏Jack的Android之旅

Android NestedScrolling机制

NestedScrolling机制现在在App的作用越来越重要,许多很漂亮的交互都是基于NestedScrolling机制进行完成的。

792
来自专栏Jack的Android之旅

一个支持Fragment,View,图片轮播的Banner

之前有一个项目中有用到轮播,不过不是简单的轮播图片就完了,而是要轮播很多个View,一开始我的想法和大家一样在github在一个算了,哈哈,不过在试用了很多个项...

1113
来自专栏开发之途

Android 解析RecyclerView(3)——以更简单的方法实现带顶部View和底部View的RecyclerView

1653
来自专栏菩提树下的杨过

fms4 p2p:图片分享

这其实是http://www.flashrealtime.com/file-share-object-replication-flash-p2p/ 中关于文件分...

1857

扫码关注云+社区