從 ViewPager 遷移至 ViewPager2

ViewPager2ViewPager 程式庫的改良版本,該版本提供了 強化功能,並解決使用 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 正確顯示修改後的集合。

迪夫普斯

ViewPager2RecyclerView 為建構基礎。 表示該 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 物件 請更新轉接程式類別以擴充適當的抽象類別,如下所示:

建構函式參數

繼承自 FragmentPagerAdapterFragmentStatePagerAdapter 一律接受單一 FragmentManager 物件 做為建構函式參數如果為 FragmentStateAdapter 擴充 ViewPager2 轉接器類別,您可以使用下列建構函式選項 參數:

  • FragmentActivity 物件或 Fragment 物件,其中含有 ViewPager2 物件也位於該物件中。在大多數的情況下,這是比較適合使用的選項。
  • FragmentManager 物件和 Lifecycle 物件。

直接從 RecyclerView.Adapter 繼承的 View 式轉接程式類別會執行以下動作: 不需要建構函式參數。

覆寫方法

您的轉接程式類別也需要覆寫 ViewPager2 的不同方法 相較於「ViewPager」的行為:

  • 請覆寫 getItemCount(),而不是 getCount()。除了名稱 則此方法未變更。
  • 請覆寫以片段為基礎的 createFragment(),而非 getItem() 轉接程式類別。請確保新的 createFragment() 方法一律為 每次呼叫函式時,都會提供新的片段例項,而非 重複使用執行個體
,瞭解如何調查及移除這項存取權。

摘要

總而言之,如要轉換 ViewPager 轉接器類別以便與 ViewPager2 搭配使用, 您必須進行下列變更:

  1. 將父類別變更為 RecyclerView.Adapter 以進行分頁瀏覽,或 FragmentStateAdapter 用於在片段之間分頁。
  2. 變更片段式轉接程式類別中的建構函式參數。
  3. 覆寫 getItemCount(),而非 getCount()
  4. 在片段式轉接程式中覆寫 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 整合。

TabLayoutViewPager2 分離,現已成為下列產品的一員: 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,請參閱下列其他資源:

範例

影片