Migrer de ViewPager vers ViewPager2

ViewPager2 est une version améliorée de la bibliothèque ViewPager qui offre des fonctionnalités améliorées et résout les problèmes courants liés à l'utilisation de ViewPager. Si votre appli utilise déjà ViewPager, lisez cette page pour en savoir plus sur migration vers ViewPager2.

Si vous souhaitez utiliser ViewPager2 dans votre appli et que vous n'utilisez pas actuellement ViewPager, consultez Glisser entre des fragments en utilisant ViewPager2 et Créer des vues à balayer avec à l'aide de ViewPager2 pour en savoir plus des informations.

Avantages de la migration vers ViewPager2

La principale raison de la migration est que ViewPager2 reçoit des au développement, contrairement à ViewPager. Cependant, ViewPager2 propose aussi plusieurs autres avantages spécifiques.

Prise en charge de l'orientation verticale

ViewPager2 prend en charge la pagination verticale en plus de la pagination horizontale traditionnelle la pagination. Vous pouvez activer la pagination verticale pour un élément ViewPager2 en définissant sa Attribut android:orientation:

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

Vous pouvez également définir cet attribut par programmation à l'aide de la méthode setOrientation() .

Orientation de droite à gauche

ViewPager2 prend en charge la pagination de droite à gauche (RTL). Pagination de droite à gauche activée automatiquement selon les paramètres régionaux, mais vous pouvez aussi activer la pagination de droite à gauche pour un élément ViewPager2 en définissant son Attribut android:layoutDirection:

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

Vous pouvez également définir cet attribut par programmation à l'aide de la méthode setLayoutDirection() .

Collections de fragments modifiables

ViewPager2 prend en charge la pagination via une collection modifiable de fragments, Appel en cours notifyDatasetChanged() pour mettre à jour l'UI lorsque la collection sous-jacente change.

Cela signifie que votre application peut modifier dynamiquement la collection de fragments et ViewPager2 affichera correctement la collection modifiée.

DiffUtil

ViewPager2 est basé sur RecyclerView, ce qui signifie qu'il a accès Utilitaire DiffUtil . Cela présente plusieurs avantages, mais cela signifie notamment Les objets ViewPager2 exploitent de manière native les animations de modification de l'ensemble de données. de la classe RecyclerView.

Migrer votre application vers ViewPager2

Procédez comme suit pour mettre à jour les objets ViewPager de votre application vers ViewPager2:

Mettre à jour les fichiers de mise en page XML

Tout d'abord, remplacez les éléments ViewPager de vos fichiers de mise en page XML par Éléments 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" />

Mettre à jour les classes d'adaptateur

Lorsque vous utilisez ViewPager, vous devez étendre la classe d'adaptateur que a fourni de nouvelles pages à l'objet. Selon le cas d'utilisation, ViewPager a utilisé trois classes abstraites distinctes. ViewPager2 n'utilise que deux classes abstraites.

Pour chaque objet ViewPager que vous convertissez en objet ViewPager2, Mettez à jour la classe de l'adaptateur pour étendre la classe abstraite appropriée comme suit:

Paramètres du constructeur

Les classes d'adaptateur basées sur des fragments qui héritent de FragmentPagerAdapter ou FragmentStatePagerAdapter accepte toujours un seul objet FragmentManager. en tant que paramètre constructeur. Lorsque vous prolongez FragmentStateAdapter pour ViewPager2, vous disposez des options suivantes pour le constructeur paramètres à la place:

  • L'objet FragmentActivity ou Fragment dans lequel ViewPager2 est présent. Dans la plupart des cas, il s'agit de la meilleure option.
  • Un objet FragmentManager et un objet Lifecycle.

Les classes d'adaptateur basées sur les vues qui héritent directement de RecyclerView.Adapter ont ne nécessitent pas de paramètre constructeur.

Ignorer les méthodes

Vos classes d'adaptateur doivent aussi remplacer différentes méthodes pour ViewPager2 par rapport à ViewPager:

  • Au lieu de getCount(), remplacez getItemCount(). À part le nom, cette méthode reste inchangée.
  • Au lieu de getItem(), remplacez createFragment() dans les requêtes basées sur des fragments les classes d'adaptateur. Assurez-vous que votre nouvelle méthode createFragment() fournit une nouvelle instance de fragment chaque fois que la fonction est appelée au lieu de la réutilisation d'instances.

Résumé

En résumé, pour convertir une classe d'adaptateur ViewPager à utiliser avec ViewPager2, vous devez apporter les modifications suivantes:

  1. Définissez la super-classe sur RecyclerView.Adapter pour la pagination des vues. FragmentStateAdapter pour la pagination des fragments.
  2. Modifiez les paramètres du constructeur dans les classes d'adaptateur basées sur des fragments.
  3. Ignorez getItemCount() au lieu de getCount().
  4. Remplacement de createFragment() au lieu de getItem() dans l'adaptateur basé sur des fragments classes.

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;
    }
}

Refactoriser les interfaces TabLayout

ViewPager2 modifie l'intégration de TabLayout. Si vous utilisent actuellement un ViewPager avec un objet TabLayout pour un affichage horizontal onglets pour la navigation, vous devez refactoriser l'objet TabLayout pour avec ViewPager2.

TabLayout a été dissocié de ViewPager2 et est désormais disponible dans le cadre de Composants Material. Pour l'utiliser, vous devez donc ajouter la dépendance appropriée à votre fichier build.gradle:

Groovy

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

Kotlin

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

Vous devez également modifier l'emplacement de l'élément TabLayout dans la hiérarchie des votre fichier de mise en page XML. Avec ViewPager, l'élément TabLayout est déclaré en tant que enfant de l'élément ViewPager ; mais avec ViewPager2, l'élément TabLayout est déclarée directement au-dessus de l'élément ViewPager2, au même niveau:

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

Enfin, vous devez mettre à jour le code qui associe l'objet TabLayout à la ViewPager. Bien que TabLayout utilise sa propre classe setupWithViewPager() pour intégrer ViewPager, elle nécessite un TabLayoutMediator à intégrer à ViewPager2.

L'objet TabLayoutMediator gère également la génération des titres de page. pour l'objet TabLayout, ce qui signifie que la classe d'adaptateur n'a pas besoin remplacer 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();
    }
    ...
}

Prendre en charge les éléments à défilement imbriqués

ViewPager2 n'est pas compatible de manière native avec les vues à défilement imbriqué dans les cas où la vue de défilement a la même orientation que l'objet ViewPager2 qui contient Par exemple, le défilement ne fonctionne pas pour une vue de défilement vertical à l'intérieur d'une objet ViewPager2 orienté verticalement.

Pour prendre en charge une vue de défilement dans un objet ViewPager2 ayant la même orientation : vous devez appeler requestDisallowInterceptTouchEvent() sur l'objet ViewPager2 lorsque vous s'attendent à faire défiler l'élément imbriqué à la place. Le défilement imbriqué ViewPager2 exemple illustre une façon de résoudre ce problème à l'aide d'une solution polyvalente mise en page de wrapper personnalisée.

Ressources supplémentaires

Pour en savoir plus sur ViewPager2, consultez les ressources supplémentaires suivantes.

Exemples

Vidéos