1. 程式人生 > >ViewPager圖片自動+手動左右無限輪播

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