Von ViewPager zu ViewPager2 migrieren

ViewPager2 ist eine verbesserte Version der ViewPager-Bibliothek mit erweiterte Funktionalität und behandelt häufige Probleme bei der Verwendung von ViewPager. Wenn deine App bereits ViewPager verwendet, findest du auf dieser Seite weitere Informationen zu wird zu ViewPager2 migriert.

Wenn Sie ViewPager2 in Ihrer App verwenden möchten und derzeit nicht ViewPager, lesen Sie den Abschnitt Zwischen Fragmenten wechseln mit ViewPager2 und Wischansichten erstellen mit mit ViewPager2. Informationen.

Vorteile der Migration zu ViewPager2

Der Hauptgrund für die Migration ist, dass ViewPager2 aktiv ist Entwicklungssupport, ViewPager jedoch nicht. ViewPager2 bietet aber auch einige weitere spezifische Vorteile.

Unterstützung der vertikalen Ausrichtung

ViewPager2 unterstützt neben herkömmlichem horizontalem Paging auch vertikales Paging Paging. Sie können vertikales Paging für ein ViewPager2-Element aktivieren, indem Sie seine Attribut android:orientation:

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

Sie können dieses Attribut auch programmatisch festlegen mithilfe der setOrientation() .

Rechts-nach-links-Unterstützung

ViewPager2 unterstützt das Seiten rechts nach links (rechts-nach-links, RTL). RTL-Paginierung ist aktiviert automatisch je nach Sprache. Sie können aber auch Aktivieren Sie RTL-Paginierung für ein ViewPager2-Element, indem Sie seine Attribut android:layoutDirection:

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

Sie können dieses Attribut auch programmatisch festlegen mithilfe der setLayoutDirection() .

Bearbeitbare Fragmentsammlungen

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

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

DiffUtil

ViewPager2 basiert auf RecyclerView, Das bedeutet, sie hat Zugriff auf die DiffUtil-Dienstprogramm . Daraus ergeben sich mehrere Vorteile, vor allem aber bedeutet es, dass ViewPager2-Objekte nutzen die Änderungsanimationen des Datasets nativ aus der Klasse RecyclerView.

Anwendung zu ViewPager2 migrieren

So aktualisieren Sie ViewPager-Objekte in Ihrer 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, hat dem -Objekt neue Seiten bereitgestellt. Je nach Anwendungsfall wurde ViewPager verwendet drei verschiedenen abstrakten Klassen. ViewPager2 verwendet nur zwei abstrakte Klassen.

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

Konstruktorparameter

Fragmentbasierte Adapterklassen, die von FragmentPagerAdapter übernehmen oder FragmentStatePagerAdapter akzeptiert immer ein einzelnes FragmentManager-Objekt. als Konstruktorparameter. Wenn Sie FragmentStateAdapter um eine ViewPager2 haben, stehen Ihnen für den Konstruktor folgende Optionen zur Verfügung: Parameter:

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

Ansichtsbasierte Adapterklassen, die direkt von RecyclerView.Adapter übernehmen, tun dies benötigen keinen Konstruktorparameter.

Überschreibungsmethoden

Ihre Adapterklassen müssen auch verschiedene Methoden für ViewPager2 überschreiben als beim ViewPager:

  • Überschreiben Sie getItemCount() anstelle von getCount(). Abgesehen vom Namen bleibt die Methode unverändert.
  • Anstelle von getItem() createFragment() im fragmentierten Modus überschreiben Adapterklassen zu erstellen. Achten Sie darauf, dass die neue createFragment()-Methode immer stellt bei jedem Aufruf der Funktion eine neue Fragmentinstanz bereit, wiederverwendbaren Instanzen.

Zusammenfassung

Zusammenfassend lässt sich sagen, dass zum Konvertieren einer ViewPager-Adapterklasse für die Verwendung mit ViewPager2 Folgendes gilt: müssen Sie folgende Änderungen vornehmen:

  1. Ändern Sie die Basisklasse in RecyclerView.Adapter, um durch die Ansichten zu blättern, oder FragmentStateAdapter zum Durchblättern von Fragmenten
  2. Ändern Sie die Konstruktorparameter in fragmentierten Adapterklassen.
  3. getItemCount() anstelle von getCount() überschreiben.
  4. createFragment() anstelle von getItem() im fragmentierten Adapter überschreiben Klassen.

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-Oberflächen refaktorieren

Mit ViewPager2 werden Änderungen an der TabLayout-Integration eingeführt. Wenn Sie Derzeit wird zur horizontalen Darstellung ein ViewPager mit einem TabLayout-Objekt verwendet. Tabs für die Navigation verwenden möchten, müssen Sie das TabLayout-Objekt für Integration mit ViewPager2.

TabLayout wurde von ViewPager2 entkoppelt und ist jetzt im Rahmen von Material-Komponenten. Wenn Sie sie verwenden möchten, müssen Sie entsprechende Abhängigkeit zu Ihrer build.gradle-Datei:

Cool

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 von in Ihrer XML-Layoutdatei ein. Mit ViewPager wird das TabLayout-Element als dem ViewPager-Element untergeordnet ist. aber mit ViewPager2 ist das TabLayout-Element direkt über dem Element ViewPager2 auf derselben Ebene 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>

Abschließend müssen Sie den Code aktualisieren, durch den das TabLayout-Objekt an die ViewPager-Objekt. Während TabLayout eine eigene setupWithViewPager() verwendet zur Integration von ViewPager verwenden, ist ein TabLayoutMediator erforderlich. Instanz für die Integration in ViewPager2.

Das TabLayoutMediator-Objekt übernimmt auch das Generieren von Seitentiteln für das TabLayout-Objekt. Das bedeutet, dass die Adapterklasse getPageTitle() überschreiben:

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 verschachtelte Scroll-Ansichten nicht nativ, wenn der hat die gleiche Ausrichtung wie das ViewPager2-Objekt, das . Beispielsweise funktioniert das Scrollen bei einer vertikalen Scroll-Ansicht innerhalb eines vertikal ausgerichtetes ViewPager2-Objekt.

So unterstützen Sie eine Scroll-Ansicht innerhalb eines ViewPager2-Objekts mit derselben Ausrichtung: du musst anrufen requestDisallowInterceptTouchEvent() für das ViewPager2-Objekt, wenn Sie wird stattdessen das verschachtelte Element gescrollt. Das verschachtelte Scrollen mit ViewPager2 Beispiel zeigt eine Möglichkeit zur Lösung dieses Problems mit einem vielseitigen Benutzerdefiniertes Wrapper-Layout.

Weitere Informationen

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

Produktproben

Videos