ViewPager2 是 ViewPager 程式庫的改良版本,該版本提供了
強化功能,並解決使用 ViewPager 的常見問題。
如果您的應用程式已使用 ViewPager,請參閱本頁進一步瞭解
正在遷移至 ViewPager2。
如果您想在應用程式中使用 ViewPager2,但目前並未使用
ViewPager,請參閱使用
ViewPager2和建立滑動檢視畫面
分頁或分頁
可能不準確或不適當
遷移至 ViewPager2 的好處
主要原因是正在遷移 ViewPager2
開發支援,ViewPager 則不在。不過,ViewPager2 也提供
幾項其他特定優勢
支援直向顯示
ViewPager2 支援除了傳統橫向分頁外,也支援垂直分頁
分頁。您可以為 ViewPager2 元素設定垂直分頁,藉此啟用該元素的垂直分頁功能
android:orientation 屬性:
<androidx.viewpager2.widget.ViewPager2
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:orientation="vertical" />
您也可以使用 setOrientation() 方法。
由右至左支援
ViewPager2 支援從右到左 (RTL) 分頁。RTL 分頁功能已啟用
自動根據語言代碼顯示適當內容,但您也可以手動
設定 ViewPager2 元素的 RTL 分頁,以啟用 RTL 分頁
android:layoutDirection 屬性:
<androidx.viewpager2.widget.ViewPager2
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layoutDirection="rtl" />
您也可以使用 setLayoutDirection() 方法。
可修改的片段集合
ViewPager2 支援透過可修改的片段集合進行分頁,
撥號中
notifyDatasetChanged()
在基礎集合變更時更新 UI。
也就是說,您的應用程式可以動態修改位於
然後 ViewPager2 正確顯示修改後的集合。
迪夫普斯
ViewPager2 以 RecyclerView 為建構基礎。
表示該 SDK 可存取
DiffUtil 公用程式
類別這麼做會帶來幾項好處
ViewPager2 物件原生使用資料集變更動畫
來自 RecyclerView 類別。
將應用程式遷移至 ViewPager2
請按照下列步驟將應用程式中的 ViewPager 物件更新為 ViewPager2:
更新 XML 版面配置檔案
首先,將 XML 版面配置檔案中的 ViewPager 元素替換成
ViewPager2 元素:
<!-- A ViewPager element -->
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- A ViewPager2 element -->
<androidx.viewpager2.widget.ViewPager2
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
更新轉接器類別
使用 ViewPager 時,您必須擴充轉接器類別,
會為物件提供新頁面視用途而定,系統會使用 ViewPager
三種不同的抽象類別ViewPager2 只會使用兩個抽象類別。
針對每個要轉換為 ViewPager2 物件的 ViewPager 物件
請更新轉接程式類別以擴充適當的抽象類別,如下所示:
- 如果
ViewPager使用PagerAdapter瀏覽檢視畫面,請使用RecyclerView.Adapter(使用ViewPager2)。 - 當
ViewPager使用FragmentPagerAdapter瀏覽一個小型檔案時 固定數量的片段,請搭配ViewPager2使用FragmentStateAdapter。 - 當
ViewPager使用FragmentStatePagerAdapter瀏覽 片段數量龐大或不明,請使用FragmentStateAdapter搭配ViewPager2。
建構函式參數
繼承自 FragmentPagerAdapter 或
FragmentStatePagerAdapter 一律接受單一 FragmentManager 物件
做為建構函式參數如果為 FragmentStateAdapter 擴充
ViewPager2 轉接器類別,您可以使用下列建構函式選項
參數:
FragmentActivity物件或Fragment物件,其中含有ViewPager2物件也位於該物件中。在大多數的情況下,這是比較適合使用的選項。FragmentManager物件和Lifecycle物件。
直接從 RecyclerView.Adapter 繼承的 View 式轉接程式類別會執行以下動作:
不需要建構函式參數。
覆寫方法
您的轉接程式類別也需要覆寫 ViewPager2 的不同方法
相較於「ViewPager」的行為:
- 請覆寫
getItemCount(),而不是getCount()。除了名稱 則此方法未變更。 - 請覆寫以片段為基礎的
createFragment(),而非getItem()轉接程式類別。請確保新的createFragment()方法一律為 每次呼叫函式時,都會提供新的片段例項,而非 重複使用執行個體
摘要
總而言之,如要轉換 ViewPager 轉接器類別以便與 ViewPager2 搭配使用,
您必須進行下列變更:
- 將父類別變更為
RecyclerView.Adapter以進行分頁瀏覽,或FragmentStateAdapter用於在片段之間分頁。 - 變更片段式轉接程式類別中的建構函式參數。
- 覆寫
getItemCount(),而非getCount()。 - 在片段式轉接程式中覆寫
createFragment(),而非getItem()類別
Kotlin
// A simple ViewPager adapter class for paging through fragments class ScreenSlidePagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) { override fun getCount(): Int = NUM_PAGES override fun getItem(position: Int): Fragment = ScreenSlidePageFragment() } // An equivalent ViewPager2 adapter class class ScreenSlidePagerAdapter(fa: FragmentActivity) : FragmentStateAdapter(fa) { override fun getItemCount(): Int = NUM_PAGES override fun createFragment(position: Int): Fragment = ScreenSlidePageFragment() }
Java
// A simple ViewPager adapter class for paging through fragments public class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter { public ScreenSlidePagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return new ScreenSlidePageFragment(); } @Override public int getCount() { return NUM_PAGES; } } // An equivalent ViewPager2 adapter class private class ScreenSlidePagerAdapter extends FragmentStateAdapter { public ScreenSlidePagerAdapter(FragmentActivity fa) { super(fa); } @Override public Fragment createFragment(int position) { return new ScreenSlidePageFragment(); } @Override public int getItemCount() { return NUM_PAGES; } }
重構 TabLayout 介面
ViewPager2 導入了 TabLayout 整合項目的變更。如果發生以下情況:
目前使用具有 TabLayout 物件的 ViewPager 顯示水平
以便瀏覽,您需要重構 TabLayout 物件,才能進行瀏覽
與 ViewPager2 整合。
TabLayout 與 ViewPager2 分離,現已成為下列產品的一員:
Material Design 元件。也就是說
適用於 build.gradle 檔案的適當依附元件:
Groovy
implementation "com.google.android.material:material:1.1.0-beta01"
Kotlin
implementation("com.google.android.material:material:1.1.0-beta01")
您也需要變更 TabLayout 元素在階層結構中的位置
您的 XML 版面配置檔案。使用 ViewPager 時,TabLayout 元素會宣告為
ViewPager 元素的子項;但如果使用 ViewPager2,則 TabLayout 元素
會直接在 ViewPager2 元素上方宣告:
<!-- A ViewPager element with a TabLayout -->
<androidx.viewpager.widget.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</androidx.viewpager.widget.ViewPager>
<!-- A ViewPager2 element with a TabLayout -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
最後,您必須更新將 TabLayout 物件附加至
ViewPager 物件。TabLayout 使用自己的 setupWithViewPager()
方法,以便與 ViewPager 整合,需要 TabLayoutMediator
執行個體,以便與 ViewPager2 整合。
TabLayoutMediator 物件也會處理產生頁面標題的工作。
如果是 TabLayout 物件,表示轉接程式類別不需要
覆寫 getPageTitle():
Kotlin
// Integrating TabLayout with ViewPager class CollectionDemoFragment : Fragment() { ... override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val tabLayout = view.findViewById(R.id.tab_layout) tabLayout.setupWithViewPager(viewPager) } ... } class DemoCollectionPagerAdapter(fm: FragmentManager) : FragmentStatePagerAdapter(fm) { override fun getCount(): Int = 4 override fun getPageTitle(position: Int): CharSequence { return "OBJECT ${(position + 1)}" } ... } // Integrating TabLayout with ViewPager2 class CollectionDemoFragment : Fragment() { ... override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val tabLayout = view.findViewById(R.id.tab_layout) TabLayoutMediator(tabLayout, viewPager) { tab, position -> tab.text = "OBJECT ${(position + 1)}" }.attach() } ... }
Java
// Integrating TabLayout with ViewPager public class CollectionDemoFragment extends Fragment { ... @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { TabLayout tabLayout = view.findViewById(R.id.tab_layout); tabLayout.setupWithViewPager(viewPager); } ... } public class DemoCollectionPagerAdapter extends FragmentStatePagerAdapter { ... @Override public int getCount() { return 4; } @Override public CharSequence getPageTitle(int position) { return "OBJECT " + (position + 1); } ... } // Integrating TabLayout with ViewPager2 public class CollectionDemoFragment : Fragment() { ... @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { TabLayout tabLayout = view.findViewById(R.id.tab_layout); new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> tab.setText("OBJECT " + (position + 1)) ).attach(); } ... }
支援巢狀捲動元素
在下列情況中,ViewPager2 原生不支援巢狀捲動檢視畫面:
捲動檢視畫面的方向與包含的 ViewPager2 物件相同
基礎架構舉例來說,捲動功能不支援 Google 應用程式中的垂直捲動檢視畫面
垂直導向 ViewPager2 物件。
如要在 ViewPager2 物件中支援相同方向的捲動檢視畫面,
你必須呼叫。
ViewPager2 物件上的 requestDisallowInterceptTouchEvent() (當您執行以下動作時)
會預期改為捲動巢狀元素ViewPager2 巢狀捲動
範例示範使用多功能資源來解決這個問題的一種方法
自訂包裝函式版面配置。
其他資源
如要進一步瞭解 ViewPager2,請參閱下列其他資源:
範例
- GitHub 上的 ViewPager2 範例
影片
- 翻頁:遷移至 MigratePager2 (2019 年 Android 開發人員高峰會)