ViewPager から ViewPager2 に移行する

ViewPager2 は ViewPager ライブラリの改良版で、次の機能を備えています。 機能が強化され、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

ViewPager2 は RecyclerView 上に構築されています。 アクセスできることを意味します 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 との統合。

TabLayout は ViewPager2 から切り離され、 マテリアル コンポーネント。つまり、これを使用するには 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 の詳細については、以下の参考リンクをご覧ください。

サンプル

動画