Von ViewPager zu ViewPager2 migrieren

ViewPager2 ist eine verbesserte Version der ViewPager-Bibliothek, die erweiterte Funktionen bietet und häufige Probleme bei der Verwendung von ViewPager behebt. Wenn Ihre Anwendung bereits ViewPager verwendet, finden Sie auf dieser Seite weitere Informationen zur Migration zu ViewPager2.

Wenn Sie ViewPager2 in Ihrer App verwenden möchten und ViewPager derzeit nicht nutzen, finden Sie weitere Informationen unter Mit ViewPager2 zwischen Fragmenten wechseln und Wischansichten mit Tabs mit ViewPager2 erstellen.

Vorteile der Migration zu ViewPager2

Der Hauptgrund für die Migration ist, dass ViewPager2 aktiven Entwicklungssupport erhält und ViewPager nicht. Allerdings bietet ViewPager2 auch einige andere spezifische Vorteile.

Unterstützung für vertikale Ausrichtung

ViewPager2 unterstützt zusätzlich zum herkömmlichen horizontalen Paging vertikales Paging. Sie können vertikales Paging für ein ViewPager2-Element aktivieren, indem Sie das entsprechende android:orientation-Attribut festlegen:

<androidx.viewpager2.widget.ViewPager2
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:orientation="vertical" />

Mit der Methode setOrientation() kann dieses Attribut auch programmatisch festgelegt werden.

Unterstützung von rechts nach links

ViewPager2 unterstützt die Seitenausrichtung von rechts nach links (RTL). Je nach Sprache wird das RTL-Seitening automatisch aktiviert. Sie können es aber auch manuell für ein ViewPager2-Element aktivieren. Dazu legen Sie das entsprechende android:layoutDirection-Attribut fest:

<androidx.viewpager2.widget.ViewPager2
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:layoutDirection="rtl" />

Mit der Methode setLayoutDirection() lässt sich dieses Attribut auch programmatisch festlegen.

Bearbeitbare Fragmentsammlungen

ViewPager2 unterstützt das Durchblättern einer änderbaren Sammlung von Fragmenten. Dabei wird notifyDatasetChanged() aufgerufen, um die UI zu aktualisieren, wenn sich die zugrunde liegende Sammlung ändert.

Das bedeutet, dass Ihre Anwendung die Fragmentsammlung zur Laufzeit dynamisch ändern kann und ViewPager2 die geänderte Sammlung korrekt anzeigt.

DiffUtil

ViewPager2 basiert auf RecyclerView und hat daher Zugriff auf die Dienstprogrammklasse DiffUtil. Dies bietet mehrere Vorteile, vor allem bedeutet es aber, dass ViewPager2-Objekte die Animationen von Dataset-Änderungen aus der RecyclerView-Klasse nativ nutzen.

App zu ViewPager2 migrieren

So aktualisierst du ViewPager-Objekte in deiner App auf ViewPager2:

XML-Layoutdateien aktualisieren

Ersetzen Sie zuerst die ViewPager-Elemente in Ihren XML-Layoutdateien durch ViewPager2-Elemente:

<!-- 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" />

Adapterklassen aktualisieren

Bei der Verwendung von ViewPager mussten Sie die Adapterklasse erweitern, über die neue Seiten für das Objekt bereitgestellt wurden. Je nach Anwendungsfall wurden bei ViewPager drei verschiedene abstrakte Klassen verwendet. ViewPager2 verwendet nur zwei abstrakte Klassen.

Aktualisieren Sie für jedes ViewPager-Objekt, das Sie in ein ViewPager2-Objekt konvertieren, die Adapterklasse, um die entsprechende abstrakte Klasse zu erweitern:

Konstruktorparameter

Fragmentbasierte Adapterklassen, die FragmentPagerAdapter oder FragmentStatePagerAdapter übernehmen, akzeptieren immer ein einzelnes FragmentManager-Objekt als Konstruktorparameter. Wenn Sie FragmentStateAdapter für eine ViewPager2-Adapterklasse erweitern, stehen stattdessen die folgenden Optionen für Konstruktorparameter zur Verfügung:

  • Das FragmentActivity- oder Fragment-Objekt, in dem sich das ViewPager2-Objekt befindet. In den meisten Fällen ist dies die bessere Option.
  • Ein FragmentManager-Objekt und ein Lifecycle-Objekt.

Für ansichtsbasierte Adapterklassen, die direkt von RecyclerView.Adapter übernommen werden, ist kein Konstruktorparameter erforderlich.

Überschreibungsmethoden

Außerdem müssen Ihre Adapterklassen für ViewPager2 andere Methoden überschreiben als für ViewPager:

  • Überschreiben Sie getItemCount() anstelle von getCount(). Abgesehen vom Namen bleibt diese Methode unverändert.
  • Überschreiben Sie createFragment() in fragmentbasierten Adapterklassen anstelle von getItem(). Achten Sie darauf, dass die neue Methode createFragment() bei jedem Aufruf der Funktion immer eine neue Fragmentinstanz bereitstellt, anstatt Instanzen zu wiederverwenden.

Zusammenfassung

Zusammenfassend lässt sich sagen, dass Sie folgende Änderungen vornehmen, um eine ViewPager-Adapterklasse zur Verwendung mit ViewPager2 zu konvertieren:

  1. Ändern Sie die Basisklasse in RecyclerView.Adapter, um durch Ansichten blättern zu können, oder in FragmentStateAdapter, um durch Fragmente zu blättern.
  2. Ändern Sie die Konstruktorparameter in fragmentbasierten Adapterklassen.
  3. getItemCount() anstelle von getCount() überschreiben.
  4. Überschreiben Sie createFragment() anstelle von getItem() in fragmentbasierten Adapterklassen.

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-Schnittstellen refaktorieren

Mit ViewPager2 wurden Änderungen an der TabLayout-Integration vorgenommen. Wenn Sie derzeit ein ViewPager mit einem TabLayout-Objekt verwenden, um horizontale Tabs für die Navigation anzuzeigen, müssen Sie das TabLayout-Objekt für die Integration in ViewPager2 refaktorieren.

TabLayout wurde von ViewPager2 entkoppelt und ist jetzt als Teil der Material Components verfügbar. Das bedeutet, dass Sie die entsprechende Abhängigkeit zu Ihrer build.gradle-Datei hinzufügen müssen, um sie verwenden zu können:

Groovig

implementation "com.google.android.material:material:1.1.0-beta01"

Kotlin

implementation("com.google.android.material:material:1.1.0-beta01")

Außerdem müssen Sie die Position des TabLayout-Elements in der Hierarchie Ihrer XML-Layoutdatei ändern. Bei ViewPager wird das TabLayout-Element als untergeordnetes Element des ViewPager-Elements deklariert. Mit ViewPager2 wird das TabLayout-Element jedoch auf derselben Ebene direkt über dem ViewPager2-Element deklariert:

<!-- 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>

Schließlich müssen Sie den Code aktualisieren, mit dem das TabLayout-Objekt an das ViewPager-Objekt angehängt wird. TabLayout verwendet für die Einbindung in ViewPager eine eigene Methode setupWithViewPager(). Für die Einbindung in ViewPager2 ist jedoch eine TabLayoutMediator-Instanz erforderlich.

Das TabLayoutMediator-Objekt übernimmt auch die Aufgabe, Seitentitel für das TabLayout-Objekt zu generieren. Das bedeutet, dass die Adapterklasse getPageTitle() nicht überschreiben muss:

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();
    }
    ...
}

Verschachtelte scrollbare Elemente unterstützen

ViewPager2 unterstützt nativ keine verschachtelten Scroll-Ansichten, wenn die Scroll-Ansicht dieselbe Ausrichtung hat wie das ViewPager2-Objekt, das sie enthält. Das Scrollen funktioniert beispielsweise nicht bei einer vertikalen Scrollansicht in einem vertikal ausgerichteten ViewPager2-Objekt.

Um eine Scroll-Ansicht innerhalb eines ViewPager2-Objekts mit derselben Ausrichtung zu ermöglichen, müssen Sie requestDisallowInterceptTouchEvent() für das ViewPager2-Objekt aufrufen, wenn Sie stattdessen durch das verschachtelte Element scrollen möchten. Das verschachtelte Scrolling-Beispiel von ViewPager2 zeigt eine Möglichkeit, dieses Problem mit einem vielseitigen benutzerdefinierten Wrapper-Layout zu lösen.

Weitere Informationen

Weitere Informationen zu ViewPager2 finden Sie in den folgenden zusätzlichen Ressourcen.

Produktproben

Videos