ViewPager使用記錄3——迴圈展示

来源:http://www.cnblogs.com/developerdaily/archive/2017/12/11/8025592.html
-Advertisement-
Play Games

ViewPager是v4支持庫中的一個控制項,相信幾乎所有接觸Android開發的人都對它不陌生。之所以還要在這裡翻舊賬,是因為我在最近的項目中有多個需求用到了它,覺得自己對它的認識不夠深刻。我計劃從最簡單的使用場景出發,記錄我到目前為止所對ViewPager的使用情況以及有關它的一些知識點。 這個系 ...


ViewPager是v4支持庫中的一個控制項,相信幾乎所有接觸Android開發的人都對它不陌生。之所以還要在這裡翻舊賬,是因為我在最近的項目中有多個需求用到了它,覺得自己對它的認識不夠深刻。我計劃從最簡單的使用場景出發,記錄我到目前為止所對ViewPager的使用情況以及有關它的一些知識點。

這個系列的代碼將存放在Github倉庫中,每篇文章對應一個分支或幾個分支。

這是第三篇文章,將討論集中有關如何使用ViewPager展示無限迴圈視圖的方法。

方法1:極大化PagerAdapter.getCount的返回值

這是最簡單的實現方法。關鍵在於重寫PagerAdapter.getCount方法,將其返回值設置為Integer.MAX_VALUE,然後通通過取模position%count的方式獲取得對應的數據進行視圖渲染。

...
@Override
public int getCount() {  
    return Integer.MAX_VALUE;
}

@Override
public Object instantiateItem(ViewGroup container, int position) {  
    int index = position % 3;
    String text = texts.get(index);
    TextView textView = new TextView(container.getContext());
    textView.setText(text);
    container.addView(textView);
    return textView;
}
...

這種方法畢竟不是真實的無限迴圈,只是虛擬了一個極大的頁數,讓用戶翻頁的時候很觸及到“世界的盡頭”。所以在初始化的時候需要完成一個關鍵初始化:

viewPager.setCurrentItem(Integer.MAX_VALUE / 2, false);  

把初始化頁面定位到世界的中央。

相關代碼在分支:03-fake-infinite-cycle可以獲取。

方法2:在數據源首尾添加重覆節點

這是實現ViewPager無限迴圈的另一種方案:通過在數據源的首尾處添加重覆的數據(在源數據前插入最後一個數據,其後插入原來的第一個數據),這兩個重覆數據的作用是在滾動過程中作為中間視圖,當滾動停止時立刻切換到最終的視圖,進入下一個滾動迴圈。

相關代碼見分支:03-infinite-cycle-with-additional-views

首先在往PagerAdapter插入數據的時候對數據進行一下處理:

public void setTexts(List<String> texts) {  
    this.texts.clear();
    if (texts == null) {
        notifyDataSetChanged();
        return;
    }

    // 只有一個數據時不迴圈
    if (texts.size() == 1) {
        this.texts.addAll(texts);

    // 多個數據,插入重覆數據
    } else if (texts.size() > 1) {
        this.texts.add(texts.get(texts.size() - 1));
        this.texts.addAll(texts);
        this.texts.add(texts.get(0));
    }

    notifyDataSetChanged();
}

其次讓ViewPager實現ViewPager.OnPageChangeListener介面,監聽滾動狀態。代碼如下:

@Override
public void onPageSelected(int position) {  
    int realCount = getCount() - 2;
    // 多於1,才會迴圈跳轉
    if ( getCount() > 1) {
        // 首位之前,跳轉到末尾(N)
        if ( position < 1) {
            position = realCount;
            viewPager.setCurrentItem(position,false);
        }
        // 末位之後,跳轉到首位(1)
        else if ( position > realCount) {
            position = 1;
            viewPager.setCurrentItem(position,false);
        }
    }
}

最後組裝一下ViewPagerPagerAdapter即可:

viewPager.setAdapter(adapter);  
viewPager.addOnPageChangeListener(adapter);  
if (adapter.getCount() > 1) {  
    viewPager.setCurrentItem(1, false);
}

註意最後的if語句,它讓ViewPager預設顯示第一頁。否則頁面將展示最後一個源數據的內容且無法向右滑動。

實際上這種方法也是有缺陷的。當用戶滑動ViewPager到源數據的最後一個節點(下標:getCount()-2)並且先要繼續滑動顯示下一個節點時,這期間ViewPager首先隨用戶手指一動正常展示我們插入的重覆內容(下標:getCount()-1),當滾動停止且觸發了onPageSelected回調,ViewPager立即切換到源數據的第一頁(下標:1)進入下一個迴圈。這會導致幾個不協調的現象:

  1. 切換到下一個迴圈的時候會破壞ViewPager的滾動動畫(如:滾動慣性動畫)。
  2. 切換前展示的緩存視圖在切換時被銷毀,切換後的視圖需要重新生成。如果這裡有需要延遲載入的內容也會導致展示不協調。
方法3:改進方法2

針對上述方法2提出的兩個缺點,在此將著重解決缺點1出現的動畫不連貫的現象,作為第三種方案進行介紹。至於缺點2可以通過緩存視圖的方式解決,就不在此贅述。

方法3的代碼見分支:03-infinite-cycle-better-practise

該方案已經滿足我目前的需求。它的關鍵點如下:

首先,如方法2一樣在數據源頭尾插入重覆節點,用於過渡。這裡我重新寫了setTexts方法,讓只有一個數據的場景也可以迴圈:

public void setTexts(List<String> texts) {  
    this.count = 0;
    this.texts.clear();
    if (texts != null && texts.size() > 0) {
        this.count = texts.size();
        for (int i = 0; i <= count + 1; i++) {
            if (i == 0) {
                this.texts.add(texts.get(count - 1));
            } else if (i == count + 1) {
                this.texts.add(texts.get(0));
            } else {
                this.texts.add(texts.get(i - 1));
            }
        }
    }
    notifyDataSetChanged();
}

接下來解決方法2的動畫不連貫的問題。註意到在方法2中在OnPageChangeListeneronPageSelected方法中處理了迴圈的跳轉邏輯。然後onPageSelectedViewPager處理ACTION_UP事件時回調的。也就是說,當用戶的手指時快速拖動後離開ViewPager時,ViewPager回調了該方法,然後還會繼續後續的衰減動畫。在這個時間點使用setCurrentItem跳轉到指定視圖必然會造成動畫停頓的問題。

把切換迴圈改在ViewPager的滾動狀態發生變化時進行。怎麼做呢?見代碼:

// count為源數據的條目
// currentItem為PagerAdapter當前選中項
@Override
public void onPageSelected(int position) {  
    currentItem = position;
}
@Override
public void onPageScrollStateChanged(int state) {  
    switch (state) {
        case ViewPager.SCROLL_STATE_IDLE://No operation
            if (currentItem == 0) {
                viewPager.setCurrentItem(count, false);
            } else if (currentItem == count + 1) {
                viewPager.setCurrentItem(1, false);
            }
            break;
        case ViewPager.SCROLL_STATE_DRAGGING: //start Sliding
            if (currentItem == 0) {
                viewPager.setCurrentItem(count, false);
            } else if (currentItem == count + 1) {
                viewPager.setCurrentItem(1, false);
            }
            break;
        case ViewPager.SCROLL_STATE_SETTLING://end Sliding
            break;
    }
}

代碼中在狀態變為停止“SCROLL_STATE_IDLE”或狀態變為開始滾動“SCROLL_STATE_DRAGGING”時處理了迴圈切換的邏輯。

這裡描述一下整個流程。如果用戶處於第一頁且繼續向右滑動手指,或者處於最後一頁且繼續向左滑動手指時,在狀態由空閑變為開始滾動“SCROLL_STATE_DRAGGING”進行切換。第一種情況,如果最終成功切換到目標頁面,那麼在狀態變為空閑時由於currentItem已經發生變化,所以不會重覆切換。第二種情況,如果沒有成功切換到目標頁面,ViewPager需要在狀態變為“SCROLL_STATE_IDLE”時再次切換回原來的視圖。

註意在初始化ViewPager時調用一下setCurrentItem(1),讓它正確顯示第一個視圖。

小結

ViewPager迴圈展示數據的方法目前就介紹到這裡。我認為方法1和方法3根據不同場景考慮是否使用。出於某種情結,我更傾向於使用方法3,畢竟方法三是查看了github中的banner庫之後總結出來的。

 

本文來自作者同步博客


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 首先,先弄清楚tnsping是什麼: Oracle Net 工具(命令)tnsping,是一個OSI會話層的工具,測試資料庫服務的命令,用來決定是否一個Oracle Net 網路服務(service)可以被接受。從某種意義上來說,tnsping 針對的 sqlnet連接,就好比為我們常用的ping ...
  • 創建自動執行存儲過程: 1.創建參數 2.刪除已有同名的作業 3. 創建作業 4.創建作業步驟 5.連接伺服器 6.創建作業調度 7.啟動作業 ALTER PROCEDURE dbo.sx_pro_AutoExecJobCreation AS Begin Declare @jobName varch ...
  • 一.背景 為了適應業務增長,資料庫數據量快速增長,性能日趨下降,穩定性不佳的實際情況,急需架構逐步演變適應未來的業務發展。 二.現狀 【穩定性】資料庫為單點,沒有高可用和穩定性方案。 【數據量大】資料庫目前400G左右,每個月大約100G的增量; 單表數據只增不刪,數據持續增長; 【業務優化,剝離難 ...
  • 用PLSQL調試存儲過程的時候,經常會遇到這個的情況,點調試後,繼續點單步都是灰色,想停下來,但是取消也要點很多次才能取消掉。 就像下麵的情況: 一直以為是個BUG,直到最近有人告訴我了真相。 出現這個問題的原因,是因為 1:調試存儲過程要發起兩個會話(運行、調試) 2:我們plsql的預設配置會話 ...
  • 最近接到一個系統全面優化的工作,此系統從開發到運維到管理(伺服器配置/架構/索引設計/日常維護)等等方面均非常優秀,在之前的一些文章中很少涉及深層次語句調優的方法和思路,那麼今天補充一篇。 廢話不多說 直接上思路步驟。 步驟一: 確定重點語句 此部分詳細說明,請參見:Expert 診斷優化系列 針對 ...
  • CREATE PROCEDURE [dbo].[P_Max] @a int, -- 輸入 @b int, -- 輸入 @Returnc int output --輸出 AS if (@a>@b) set @Returnc =@a else set @Returnc =@b -- 調用 declare... ...
  • < > 尖括弧,用於分隔字元串,字元串為語法元素的名稱,SQL語言的非終結符。::= 定義操作符。用在生成規則中,分隔規則定義的元素和規則定義。 被定義的元素位於操作符的左邊,規則定義位於操作符的右邊。[ ] 方括弧表示規則中的可選元素。方括弧中的規則部分可以明確指定也可以省略。{ } 花括弧聚集規 ...
  • https://www.cnblogs.com/Joetao/articles/2250516.html 本質上沒區別。只是函數有如:只能返回一個變數的限制。而存儲過程可以返回多個。 而函數是可以嵌入在sql中使用的,可以在select中調用,而存儲過程不行。 執行的本質都一樣。 函數限制比較多,比 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...