(出處:http://www.cnblogs.com/linguanh)android
前序:git
網上的這類 ViewPager 不少,可是不少都不夠好,體如今 bug多、對少頁面不支持,例如1~2張圖片、功能整合不全(無限+頁碼)等等,本類由我從零到無完成的,基本已找完 bug,註釋豐富,方便你們理解。github
特色:數組
1,代碼量少 , 共兩個類,約合 310 行代碼 (除去註釋)app
2,可擴展 , 再加個 handler 便可實現自動輪播ide
3,時間複雜度低oop
4,耦合度低,只依賴了 imageLoader,能夠本身切換佈局
5,關鍵點皆給出了詳細註釋,方便二次開發ui
功能:this
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 連接: