一行代码引入 ViewPager 无限循环 + 页码显示
(出处:http://www.cnblogs.com/linguanh)
前序:
网上的这类 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。
package cn.share.bananacloud.coustomViews.coustomEdittextInput.MyViewPager; import android.app.Activity;
import android.support.v4.view.PagerAdapter;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup; /**
* Created by 林冠宏 on 2016/4/9.
*
* viewPager 无限循环
*
*/ public class LoopViewpagerAdapter extends PagerAdapter{ private int images;
private String[] imageUrls;
private View[] views;
private boolean isLooper;
private LayoutInflater layoutInflater;
private getItemViewListener getItemViewListener; public LoopViewpagerAdapter(
Activity activity,
String[] imageUrls,
boolean isLooper, /** 是否进行无限循环 */
getItemViewListener getItemViewListener)
{
this.isLooper = isLooper;
this.images = imageUrls.length;
this.layoutInflater = activity.getLayoutInflater();
this.imageUrls = imageUrls;
views = new View[images];
this.getItemViewListener = getItemViewListener;
} @Override
public int getCount() {
if(isLooper){
if(images<3){ /** 1~2 张图片的情况 强制不开启循环 */
return images;
}else {
return 65535; /** 设置足够大 2^32 */
}
}else{
return images;
}
} /** 调用顺序 destroyItem -> instantiateItem */ @Override
public void destroyItem(ViewGroup container, int position, Object object) {
Log.d("zzzzz","destroy "+position);
container.removeView((View) object); /** 和 instantiateItem 相照应,这个是移除,不用担心内存会累加 */
} @Override
public Object instantiateItem(ViewGroup container,int position) {
Log.d("zzzzz", "position " + position);
if(isLooper && images==3){
/** 3张的特殊处理,在先右滑了一定张数后,再左滑,此时初始化的 距离当前位置 的第前2张和后面一张会重复 (x-2) == (x+1) */
View view = getItemViewListener.getItemView(layoutInflater, container, imageUrls[position%images], position);
container.addView(view);
return view;
}else {
if (position < images) {
if (views[position] == null) {
views[position] = getItemViewListener.getItemView(layoutInflater, container, imageUrls[position], position);
}
} else if (position == images && isLooper) { /** 解决由 setCurrentItem 引发的问题 */
/** 时间复杂度不高,每经过一次,进入一次 */
/** 如果看大图vp 从临界最大值点击进来,此时没有之前的 view 赋值,直接 view[max-1] 会造成 空指针 exception,这是会初始化的有 max-2,max,max-1 */
/*if(images>2){ // 最小情况的判断,因为此时的 container 还没有移除下标 0 的图片,再添加的话会造成不能重复添加的异常
views[0] = getItemViewListener.getItemView(layoutInflater,container,imageUrls[0],0);
}else{ // 刚好是 2 张,手动移除下标 0 }*/
/** 如果 共4张图,此时 positon = 3 setCurrentItem() 就会造成加载了 4-2,4,4-1,4 在 view[] 是越界状态,故需要手动赋值 0,2和3 也初始化了,但是 1 没
* 若一直右滑,到 下标 1 便会抛 Cannot add a null child view to a ViewGroup,所以要 加上 views[images - 3] 也初始化
* */
views[0] = getItemViewListener.getItemView(layoutInflater, container, imageUrls[0], 0);
views[images - 3] = getItemViewListener.getItemView(layoutInflater, container, imageUrls[images - 3], 0);
container.addView(views[0]); /** add 0 不会有问题, */
return views[0];
}
} container.addView(views[position%images]);
return views[position%images];
} @Override
public boolean isViewFromObject(View view, Object o){
return view.equals(o);
} public interface getItemViewListener{
View getItemView(LayoutInflater layoutInflater,ViewGroup container,final String url,final int position);
} }
MyViewPager 类,无父类,内部使用了 LoopViewpagerAdapter ,在无限循环的基础上,附加实现了页码小点的显示。
package cn.share.bananacloud.coustomViews.coustomEdittextInput.MyViewPager; import android.app.Activity;
import android.app.AlertDialog;
import android.graphics.Bitmap;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView; import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener; import cn.share.bananacloud.R;
import cn.share.bananacloud.common.commonDataHelper;
import cn.share.bananacloud.coustomViews.coustomEdittextInput.zoomImageView.PhotoView;
import cn.share.bananacloud.tools.imageLoderHelper; /**
* Created by 林冠宏 on 2016/4/9.
*
* viewPager 无限滑动 + 点击看大图,仍可滑动 + 当前张号页码
*
*/ public class MyViewPager { private Activity activity;
private String[] imageUrls;
protected ImageLoader imageLoder = null;
private ViewPager viewPager;
private int limitTemp = 0; /** 临界中间值 */
private int picnum;
private boolean unClickLooper = false;
private boolean ClickLooper = false; public MyViewPager(
Activity activity,
ViewPager viewPager,
ImageLoader imageLoder,
String[] imageUrls
){
this.activity = activity;
this.imageUrls = imageUrls;
this.imageLoder = imageLoder;
this.viewPager = viewPager;
picnum = imageUrls.length;
} public MyViewPager setUnClickLooper(boolean unClickLooper){
this.unClickLooper = unClickLooper;
return this;
} public MyViewPager setClickLooper(boolean ClickLooper){
this.ClickLooper = ClickLooper;
return this;
} public void init(){
viewPager.setAdapter
(
new LoopViewpagerAdapter
(
activity,
imageUrls,
unClickLooper,
new LoopViewpagerAdapter.getItemViewListener() {
@Override
public View getItemView(LayoutInflater layoutInflater, ViewGroup container, final String url, final int position) {
View view = layoutInflater.inflate(R.layout.cy_item_main_image, container, false);
ImageView imageView = (ImageView) view.findViewById(R.id.image);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int temp = position%picnum; /** 记得取余数 position 在无限循环的模式不是 0 ~ picnum */
if(temp==0 && position!=0){
showVPimage(picnum-1);
}else{
showVPimage(temp);
} }
});
final ProgressBar spinner = (ProgressBar) view.findViewById(R.id.loading); imageLoder.displayImage(url, imageView,
imageLoderHelper.getLoderOption(commonDataHelper.phoneWidth, R.drawable.hot_live_default_image, 0), new SimpleImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri, View view) {
spinner.setVisibility(View.VISIBLE);
Log.d("zzzzz", "onLoadingStarted");
} @Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
spinner.setVisibility(View.GONE);
} @Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
Log.d("zzzzz", "onLoadingComplete "+imageUri);
spinner.setVisibility(View.GONE);
}
});
return view;
}
}
)
); viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int i, float v, int i1) { } @Override
public void onPageSelected(int i) { /** 先于 instantiateItem 执行 */
TextView nowCount = (TextView) activity.findViewById(R.id.nowCount);
if((i+1)%picnum==0){
nowCount.setText("" + picnum + " /");
}else {
nowCount.setText("" + (i + 1) % picnum + " /");
}
} @Override
public void onPageScrollStateChanged(int i) { }
});
} private void showVPimage(int positon) {
final AlertDialog dlg = new AlertDialog.Builder(activity).create(); View localView = LayoutInflater.from(activity).inflate(R.layout.viewpager, null); localView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
dlg.dismiss();
return false;
}
}); ViewPager viewPager = (ViewPager) localView.findViewById(R.id.imageContainer);
final LinearLayout pointContainer = (LinearLayout) localView.findViewById(R.id.pointContainer);
for(int i=0;i<picnum;i++){
ImageView imageView = (ImageView) LayoutInflater.from(activity).inflate(R.layout.viewpager_point,pointContainer,false);
pointContainer.addView(imageView);
}
viewPager.setAdapter
(
new LoopViewpagerAdapter
(
activity,
imageUrls,
ClickLooper,
new LoopViewpagerAdapter.getItemViewListener() {
@Override
public View getItemView(LayoutInflater layoutInflater, ViewGroup container, String url, int position) {
View view = layoutInflater.inflate(R.layout.show_big_pic, container, false);
PhotoView imageView = (PhotoView) view.findViewById(R.id.bigImage);
imageView.setdimissDialog(new PhotoView.dimissDialog() {
@Override
public void doDimissDialog() {
dlg.dismiss();
}
});
try {
imageLoder.displayImage
(
url,
imageView,
imageLoderHelper.getLoderOption(commonDataHelper.phoneWidth+50, R.drawable.hot_live_default_image,0)
);
} catch (Exception ignored){}
return view;
}
}
)
);
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int i, float v, int i1) { } @Override
public void onPageSelected(int i) { /** 先于 instantiateItem 执行 */
Log.d("onPageSelected","onPageSelected ->"+i);
/** 为了减少 CPU 和 内存的 绘图消耗,这里不采用 for 等循环的方式改 点背景,改用条件语句 */
if(ClickLooper){
Log.d("onPageSelected","i is ->"+i +" limitTemp is "+limitTemp);
/** 循环情况临界点的颜色恢复 */
if((i % picnum)==(picnum-1) && limitTemp == 0){ /** 左滑 */
((ImageView) pointContainer.getChildAt(0)).setImageResource(R.drawable.white_point_xml);
}else {
if (i >= picnum && i % picnum == 0) { /** 右滑 */
((ImageView) pointContainer.getChildAt(picnum - 1)).setImageResource(R.drawable.white_point_xml);
}
}
}
i = i % picnum;
((ImageView) pointContainer.getChildAt(i)).setImageResource(R.drawable.color_point);
if (i != 0 && i != picnum - 1) { /** 非临界值,两边都要修改 */
((ImageView) pointContainer.getChildAt(i>limitTemp ? i-1:i+1)).setImageResource(R.drawable.white_point_xml);
}else {
((ImageView) pointContainer.getChildAt(i==picnum-1 ? i-1:i+1)).setImageResource(R.drawable.white_point_xml);
}
limitTemp = i;
} @Override
public void onPageScrollStateChanged(int i) { }
});
viewPager.setCurrentItem(positon);
((ImageView)pointContainer.getChildAt(positon)).setImageResource(R.drawable.color_point); Window localWindow = dlg.getWindow();
localWindow.getAttributes();
dlg.show();
localWindow.setContentView(localView);
localWindow.setGravity(17);
localWindow.setLayout(-1, -1);
} }
Demo项目 github 链接:
https://github.com/af913337456/lghLoopViewPager?files=1
一行代码引入 ViewPager 无限循环 + 页码显示的更多相关文章
- Android实现ViewPager无限循环滚动回绕
Android实现ViewPager无限循环滚动回绕 Android系统提供的ViewPager标准方式是左右可以自由滑动,但是滑动到最左边的极限位置是第一个page,滑动到最右边的位置是最后一 ...
- 详细分析Android viewpager 无限循环滚动图片
由于最近在忙于项目,就没时间更新博客了,于是趁着周日在房间把最近的在项目中遇到的技术总结下.最近在项目中要做一个在viewpager无限滚动图片的需求,其实百度一下有好多的例子,但是大部分虽然实现了, ...
- ViewPager 无限循环
Overview 我们在使用ViewPager来制作图片轮播的时候,常常为ViewPager不能一直无限循环的问题所苦恼.对于这个问题,目前从网上找到了两个思路来解决: 将 ViewPager 的Co ...
- Android Studio发布项目到jcenter,一行代码引入Module
前面我们使用自己封装的okhttp项目时候,只需要app/build.gradle文件中加一行代码就能使用项目. compile 'com.ansen.http:okhttpencapsulation ...
- ViewPager 无限循环遇到的坑 viewpager.setOffscreenPageLimit(2);
viewpager.setOffscreenPageLimit(limit);这个方法,是表示viewpage除了当前显示的页面外,左右个预加载的页面个数,也就是 为limit=2时表示当前一共加载了 ...
- viewpager双层嵌套,子viewpager无限循环无法手动滑动
项目中首页是用viewpager+fragment集成的,第一个fragment有广告轮播图使用viewpager实现的,开始就遇到是广告图无法手动滑动,事件被外层的viewpager拦截响应切换到下 ...
- Android无限循环轮播广告位Banner
Android无限循环轮播广告位Banner 现在一些app通常会在头部放一个广告位,底部放置一行小圆圈指示器,指示广告位当前的页码,轮播展示一些图片,这些图片来自于网络.这个广告位banner ...
- 利用jQuery实现图片无限循环轮播(不借助于轮播插件)
原来我主要是用Bootstrap框架或者swiper插件实现轮播图的功能,而这次是用jQuery来实现图片无限循环轮播! 用到的技术有:html.css.JavaScript(少).jQuery(主要 ...
- EF webapi json序列化 表间相互引用 无限循环问题解决方案
WebApiConfig.cs中加入 如下代码即可解决无限循环问题 var json = config.Formatters.JsonFormatter; // 解决json序列化时的循环引用问题 j ...
随机推荐
- accept_mutex与性能的关系 (nginx)
注:运行环境CentOS 6+ 背景 在对启动了20个worker的nginx进行压力测试的时候发现:如果把配置文件中event配置块中的accept_mutex开关打开(1.11.3版 ...
- jq跑马灯效果
这几天公司产品有个无缝循环滚动的广告跑马灯要做,最开始想到的是<marquee>标签,但在PC端正常,在安卓广告屏上却怎么都跑不动,后来用的css3的animation,结果也是PC端及其 ...
- ASP.NET Core的路由[2]:路由系统的核心对象——Router
ASP.NET Core应用中的路由机制实现在RouterMiddleware中间件中,它的目的在于通过路由解析为请求找到一个匹配的处理器,同时将请求携带的数据以路由参数的形式解析出来供后续请求处理流 ...
- javascript中的继承与深度拷贝
前言 本篇适合前端新人,下面开始...... 对于前端新手来说(比如博主),每当对js的对象做操作时,都是一种痛苦,原因就是在于对象的赋值是引用的传递,并非值的传递,虽然看上去后者赋值给了前者,他们就 ...
- [.NET] 利用 async & await 的异步编程
利用 async & await 的异步编程 [博主]反骨仔 [出处]http://www.cnblogs.com/liqingwen/p/5922573.html 目录 异步编程的简介 异 ...
- php报错 ----> Call to undefined function imagecreatetruecolor()
刚才在写验证码的时候,发现报错,然后排查分析了一下,原来是所用的php版本(PHP/5.3.13)没有开启此扩展功能. 进入php.ini 找到extension=php_gd2.dll ,将其前面的 ...
- Linux常用命令操作
系统信息 arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2) uname -r 显示正在使用的内核版本 dmidecode -q 显示硬件系统部件 - (SMBIOS ...
- MATLAB中绘制质点轨迹动图并保存成GIF
工作需要在MATLAB中绘制质点轨迹并保存成GIF以便展示. 绘制质点轨迹动图可用comet和comet3命令,使用例子如下: t = 0:.01:2*pi;x = cos(2*t).*(cos(t) ...
- Android之文件数据存储
一.文件保存数据介绍 Activity提供了openFileOutput()方法可以用于把数据输出到文件中,具体的实现过程与在J2SE环境中保存数据到文件中是一样的.文件可用来存放大量数据,如文本.图 ...
- 如何开发一个Jquery插件
Jquery有两种开发插件的方法: 1.jquery.fn.extend(object); 2.jquery.extend(object); 第一种方法是给Jquery对象添加方法,jquery.fn ...