ViewPager圖片自動+手動左右無限輪播
寫在前面:
最近做的一個小專案有圖片輪播的需求,各種查資料發現大部分都是通過設定adapter的getCount方法返回Integer.MAX_VALUE實現的。很顯然,這種方法有很多弊端,比如很容易ANR。或者採用其他方法,但在首頁和尾頁的跳轉不夠自然。那麼有沒有比較好的方法呢?在現有方法的基礎上,加上自己的思考和改進,我終於很好的實現了ViewPager圖片輪播。趁著週末分享給大家,歡迎批評和指正。
一、主要思想
首先,很容易想到的是,要想讓尾頁左滑到首頁、首頁右滑到尾頁有一個平穩的過渡過程,那麼在首頁尾頁的兩邊必須存在著對應要跳轉的頁面,然後跳轉完成後我們再“偷偷”替換為要顯示的真實頁面(兩者頁面顯示內容一樣,只是位置不一樣,“偷偷”指的是使用者不可見,在內容不變的情況下替換了頁面的位置)。
如上圖所示,假定現在想顯示4張圖片,分別為view0到view3。根據上面的思想:
(1)我們可以在adapter中額外多加兩個view,即如圖中的紅色的view3和view0。這樣position1的view0很容易過渡到position0的view3,同理尾頁到首頁的過渡也很自然。
(2)第1步之後,我們很輕易的發現一個問題:滑到position0時,右滑之後並沒有對應的view可以顯示,同理position5。這就需要把position0的view3偷偷換成position4的view3,這樣position0的右滑也就是position4的右滑,即滑到view2,很好的滿足了設想的需求。
二、如何實現左右輪播
(1)要實現第一步,只要重寫adapter的一些方法即可。
private class ImagePagerAdapter extends PagerAdapter{
private String[] images;
private LayoutInflater inflater;
public ImagePagerAdapter(String[] images) {
this.images = images;
this.inflater = getLayoutInflater();
}
@Override
public int getCount() {
//返回實際要顯示的圖片數+2
return images.length + 2;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
//注意不要remove 否則容易閃屏
// ((ViewPager)container).removeView((View) object);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View mView = View.inflate(getApplicationContext(),R.layout.activity_uil_viewpager_item,null);
//這是重點
int realPosition = (position - 1 + images.length)%images.length;
ImageView imageView = (ImageView) mView.findViewById(R.id.myimage);
final ProgressBar bar = (ProgressBar) mView.findViewById(R.id.loading);
mView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG,"hahaha click");
}
});
//通過UIL載入圖片
imageLoader.displayImage(images[realPosition], imageView, ImageLoaderHelper.getInstance(getApplicationContext()).getSimpleDisplayImageOptions(),
new SimpleImageLoadingListener() {
@Override
public void onLoadingStarted(String imageUri, View view) {//開始載入的時候執行
bar.setVisibility(View.VISIBLE);
}
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {//載入成功的時候執行
bar.setVisibility(View.GONE);
}
@Override
public void onLoadingCancelled(String imageUri, View view) {//載入取消的時候執行
super.onLoadingCancelled(imageUri, view);
}
@Override
public void onLoadingFailed(String imageUri, View view, FailReason failReason) {//載入失敗的時候執行
String message = null;
switch (failReason.getType()){//載入失敗型別
case IO_ERROR:// 檔案I/O錯誤
message = "IO_ERROR";
break;
case DECODING_ERROR:// 解碼錯誤
message = "DECODING_ERROR";
break;
case NETWORK_DENIED:// 網路延遲
message = "NETWORK_DENIED";
break;
case OUT_OF_MEMORY:// 記憶體不足
message = "OUT_OF_MEMORY";
break;
case UNKNOWN:// 原因不明
default:
message = "UNKNOWN";
break;
}
bar.setVisibility(View.GONE);
}
}, new ImageLoadingProgressListener() {
@Override
public void onProgressUpdate(String s, View view, int i, int i1) {//在這裡更新 ProgressBar的進度資訊
int progress = 100*i/i1;
bar.setProgress(progress);
}
});
((ViewPager)container).addView(mView,0);
return mView;
}
}
以上程式碼,關於圖片資源的UIL獲取可忽略。比較重要的是getCount()返回實際要顯示的圖片數+2,這樣才能在首尾附加兩個view。另外一個是在instantiateItem()方法中int realPosition = (position - 1 + images.length)%images.length;這裡的realPosition對應要顯示View的index。由上圖,這個關係也是顯而易見的。此外,還要注意的是在destroyItem()中不要removeView否則快速滑動的時候容易出現閃屏。
PS:由上圖可以發現,應該初始化ViewPager.setCurrentItem(1);才能從預設的第一頁開始播放。
(2)至於第二步,“偷偷”替換的過程,主要和PageChangeListener的三個要實現的方法有關,這裡先把主要程式碼附上。
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
/**
* 當頁面在滑動了呼叫
* @param position 當前頁面,即點選滑動的頁面
* @param positionOffset 當前頁面偏移的百分比
* @param positionOffsetPixels 當前頁面偏移的畫素位置
*/
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (position == Constants.images.length && positionOffset > 0.99) {
//在position4左滑且左滑positionOffset百分比接近1時,偷偷替換為position1(原本會滑到position5)
mViewPager.setCurrentItem(1, false);
} else if (position == 0 && positionOffset < 0.01) {
//在position1右滑且右滑百分比接近0時,偷偷替換為position4(原本會滑到position0)
mViewPager.setCurrentItem(4, false);
}
}
/**
* This method will be invoked when a new page becomes selected. Animation is not
* necessarily complete. 一般在滑動30%的時候就會呼叫
*
* @param position Position index of the new selected page.
*/
@Override
public void onPageSelected(int position) {
//當有手動操作時,remove掉之前auto的runnable。延遲將由手動的這次決定。
//總之,一個頁面selected之後 最多隻有一個runnable,要把多的remove掉
handler.removeCallbacks(runnable);
Log.d(TAG, "onPageSelected,page:" + position);
if (position != Constants.images.length+1 && position != 0){
handler.postDelayed(runnable,3*1000);
}
}
@Override
public void onPageScrollStateChanged(int state) {
switch (state) {
case 0://什麼都沒做 空閒狀態
break;
case 1://正在滑動
break;
case 2://滑動完畢
break;
}
}
});
onPageScrolled:
頁面滾動的時候就會呼叫,三個引數如註釋所示。值得注意的是:
關於左滑:在一個頁面中,比如position4,左滑過程中onPageScrolled的position引數一直為4,positionOffset由0遞增無限接近1。
關於右滑:比如當前頁面在position1,右滑過程中,position引數立刻變為0,且positionOffset由1遞減至0.
(這裡為了便於幫助理解首尾頁跳轉邏輯,特地選了position1和position4,其實對所有位置都是這樣。大家可以自己左右滑動觀察列印資訊,這一點對頁面跳轉的條件的理解很重要),這裡positionOffset > 0.99和positionOffset < 0.01的限制條件是為了在整個頁面幾乎全部顯示出來之後默默替換,否則頁面轉換不夠自然。此外,不能夠限定為1和0,所以我取了比較接近的數值。
此外,mViewPager.setCurrentItem(1, false);中第二個引數為false表示頁面切換無動畫,這裡由於當前顯示內容和待切換內容一致,因而使用者察覺不到位置替換過程。引數為true,則為平滑過渡。
PS:這裡易犯的錯誤是,在onPageSelected方法中實現頁面切換。其實這個方法在頁面還在滑動的過程中就會呼叫(可見官方文件說明,我這裡多次觀察在偏移量為30%左右的時候就會呼叫),這樣會有明顯不自然的切換效果。
三、如何實現自動輪播
關於自動輪播,一般都是採用handler+timer的方法。還應當注意的是,手動滑動後應該重新計時。
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
Log.d(TAG, "have received a msg");
int curindex = (mViewPager.getCurrentItem()+1)%(Constants.images.length+2);
mViewPager.setCurrentItem(curindex,true);
}
};
Runnable runnable = new Runnable() {
@Override
public void run() {
Message message = new Message();
handler.sendMessage(message);
}
};
頁面載入的時候先呼叫一次 handler.postDelayed(runnable, 3 * 1000);實現一次頁面自動切換,然後重點在onPageSelected()方法中的處理,實現自動輪播。
@Override
public void onPageSelected(int position) {
//當有手動操作時,remove掉之前auto的runnable。延遲將由手動的這次決定。
//總之,一個頁面selected之後 最多隻有一個runnable,要把多的remove掉
handler.removeCallbacks(runnable);
Log.d(TAG, "onPageSelected,page:" + position);
if (position != Constants.images.length+1 && position != 0){
handler.postDelayed(runnable,3*1000);
}
}
注意前面的handler.removeCallbacks(runnable);是很必要的,防止手動+自動會產生多餘的post從而加快頁面切換間隔(之前忽略了這點糾結了很久)。
相關推薦
ViewPager圖片自動+手動左右無限輪播
寫在前面: 最近做的一個小專案有圖片輪播的需求,各種查資料發現大部分都是通過設定adapter的getCount方法返回Integer.MAX_VALUE實現的。很顯然,這種方法有很多弊端,比如很容易ANR。或者採用其他方法,但在首頁和尾頁的跳轉不夠自然。那麼
Android 輪播圖 實現 一 :三方框架 自定義viewPager (CircleViewPager.)實現無限輪播。
使用流程:1 。 gradle中新增依賴compile 'com.zhpan.library:viewpager:1.0.3'2.在xml檔案中新增如下程式碼:<com.zhpan.viewpager.view.CircleViewPager andr
viewpager實現畫廊(中間圖片全部顯示,左右顯示一部分b佈局)無限輪播效果
一、佈局 <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:la
ViewPager輪播圖:自動無限輪播,手指長按停止,實現點選事件(實用版)
此Demo是自定義的viewpager,實現功能如下:無限自動輪播,pager點選事件處理,手指長按停止自動輪播,手指擡起恢復自動輪播; 幾乎可以滿足目前專案中的要求;大家可以直接使用; 整個Demo分兩大類,一個是自定義的ViewPager,一個是MainActivi
Android自動無限輪播圖viewpager的使用
1、具體步驟 說下大概實現步驟,一般我們有兩種,一種是viewpager+作為遊標的點 。另外一種是重寫viewpager。 效果圖: 1.1 佈局,直接viewpager+一個viewgroup就好。<RelativeLayout xmlns:an
jquery圖片輪播,點選左右按鈕輪播,可控制是否自動播放,是否迴圈輪播(自寫)
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>輪播</title> <
自動無限輪播廣告欄
自動滑動廣告欄是比較常用的功能之一,方法一是使用的是一個第三方工具AutoScrollViewPager,方法二使用的是自定義控制元件實現需要的要求. 1.AutoScrollViewPager 第三方庫,github地址: https://github.com/Trinea/an
Viewpager無限輪播+XlistView
前提 寫許可權 <uses-permission android:name="android.permission.INTERNET"/> 寫name屬性 android:name=".App" 寫依賴 或導xlistview module NewsBean
圖片無限輪播
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=devic
從網路獲取圖片實現無限輪播 外賣公眾號開發找捌躍科技
//網路請求資料工具類 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader
Banner載入圖片無限輪播
implementation 'com.youth.banner:banner:1.4.9' implementation 'com.github.bumptech.glide:glide:3.7.0' public class Gild extends ImageLoader {
iOS開發之三個Button實現圖片無限輪播(參考手機淘寶,Swift版)
這兩天使用Reveal工具檢視"手機淘寶"App的UI層次時,發現其圖片輪播使用了三個UIButton的複用來實現的圖片迴圈無縫滾動。於是乎就有了今天這篇部落格,看到“手機淘寶”這個幻燈片的UI層級時,就想要動手使用三個Button來實現一下,當然本篇部落格使用是Swift語言,思路就是使用三個Button進
使用CollectionView實現無限輪播圖(自動和手動輪播)
使用UICollectionView封裝了一個無限迴圈的輪播圖,實現手動輪播和定時器自動輪播,傳入圖片陣列和標題陣列,即可實現圖片文字的輪播圖,並有點選事件,實現代理方法可實現點選事件的處理 ///呼叫 class HomeViewController: B
Android 超簡單自動無限輪播圖
ArrayList<String> Adlist = new ArrayList<>(); mBannerView.setImgUrlData(Adlist); mBannerView.setOnHeaderViewClickLis
viewpager從入門到精通3 無限輪播viewpager
在上一篇部落格 viewpager從入門到精通2 無限數量viewpager 中我們擁有了無限數量的viewpager這篇我們要做個處理讓這個無限數量的viewpager變為無限輪播viewpager。讓它滑動起來。 我的思路是讓handler一直髮送訊息當接
ViewPager最簡單的無限輪播
第一步:重寫一下ViewPager package com.diction.app.android.view.indicator; import android.content.Context; import android.support.v4.view.ViewP
簡單PullToRefreshListView+ViewPager無限輪播
//主佈局 <?xml version="1.0" encoding="utf-8"?> <LinearLayout android:id="@+id/llll" xmlns:android="http://schemas.android.com/apk/
Banner 網路圖片無限輪播 ImageLoader
1---新增依賴 compile 'com.youth.banner:banner:1.4.9' //Banner最新版本 compile 'com.nostra13.universalimageloader:universal-image-loader:1
工具篇——InfiniteShufflingViewPager(用於自動無限輪播的輪播圖)
寫程式碼的四點: 1.明確需求。要做什麼? 2.分析思路。要怎麼做?(1,2,3……) 3.確定步驟。每一個思路要用到哪些語句、方法和物件。 4.程式碼實現。用具體的語言程式碼將思路實現出來。學習新技術的四點: 1.該技術是什麼?
安卓實現廣告欄圖片無限輪播播放效果
//經常在安卓app中頁面上方放置一個廣告欄,用到的無限輪播程式碼: public class MainActivity extends Activity {// 廣告控制元件private MyPagerGalleryView gallery;// 圓點容器privat