ViewPager から ViewPager2 に移行する

ViewPager2ViewPager ライブラリの改良版で、次の機能を備えています。 機能が強化され、ViewPager の使用に関する一般的な問題に対処しています。 アプリですでに ViewPager を使用している場合は、このページで詳細を確認してください ViewPager2 に移行します。

アプリで ViewPager2 を使用する予定で、現在 ViewPager については、 ViewPager2 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() メソッドを呼び出します。

RTL(右から左)のサポート

ViewPager2 は、RTL(右から左)方向ページングをサポートしています。RTL ページングが有効 自動的に設定されますが、手動で ViewPager2 要素の 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 は変更されたコレクションを正しく表示します。

DiffUtil

ViewPager2RecyclerView 上に構築されています。 アクセスできることを意味します 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 を使用するときは、Terraform でインフラストラクチャを 新しいページがオブジェクトに渡されました。ユースケースによっては、ViewPager を使用 3 種類の抽象クラスがあります。ViewPager2 の場合、使用する抽象クラスは 2 つだけで済みます。

ViewPager2 オブジェクトに変換する ViewPager オブジェクトごとに、 アダプタクラスを更新して、適切な抽象クラスを次のように拡張します。

コンストラクタ パラメータ

FragmentPagerAdapter を継承するフラグメント ベースのアダプタクラス、または FragmentStatePagerAdapter は常に単一の FragmentManager オブジェクトを受け入れます。 として渡されます。FragmentStateAdapter を拡張して ViewPager2 アダプタクラスを使用している場合、コンストラクタに次のオプションがあります。 パラメータを使用してください。

  • FragmentActivity オブジェクトまたは Fragment オブジェクト。 ViewPager2 オブジェクトが存在する。ほとんどの場合、この方法をおすすめします。
  • FragmentManager オブジェクトと Lifecycle オブジェクト。

RecyclerView.Adapter から直接継承するビューベースのアダプタクラスは、 コンストラクタ パラメータは不要です。

メソッドをオーバーライド

アダプタクラスは、ViewPager2 のさまざまなメソッドをオーバーライドする必要もあります。 ViewPagerとの比較:

  • getCount() ではなく、getItemCount() をオーバーライドします。名前がわからなくても、 このメソッドは変更されません。
  • getItem() ではなく、フラグメント ベースで createFragment() をオーバーライドする 使用します。新しい createFragment() メソッドが常に は、関数が呼び出されるたびに、新しいフラグメント インスタンスを インスタンスを再利用できます。
で確認できます。

概要

まとめると、ViewPager アダプター クラスを ViewPager2 で使用できるように変換するには、次のようにします。 次の変更を行う必要があります。

  1. ビューのページングを行うには、スーパークラスを RecyclerView.Adapter に変更します。 FragmentStateAdapter: フラグメントのページングに使用します。
  2. フラグメント ベース アダプター クラスのコンストラクタ パラメータを変更します。
  3. getCount() ではなく getItemCount() をオーバーライドします。
  4. フラグメント ベースのアダプターで getItem() ではなく createFragment() をオーバーライドする 。

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 から切り離され、 マテリアル コンポーネント。つまり、これを使用するには 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 オブジェクトと同じになります。 できます。たとえば、内部の縦方向のスクロール ビューでスクロールが機能しません。 縦向きの ViewPager2 オブジェクト。

同じ向きの ViewPager2 オブジェクト内でスクロール ビューをサポートするには、次のようにします。 呼び出します ViewPager2 オブジェクトに対する requestDisallowInterceptTouchEvent() ネストされた要素がスクロールされるとは限りません。ViewPager2 のネストされたスクロール サンプルは、この問題を多目的に解決する 1 つの方法を示しています。 カスタム ラッパー レイアウト

参考情報

ViewPager2 の詳細については、以下の参考リンクをご覧ください。

サンプル

動画