Au secours mon ViewPager Android affiche n'importe quoi quand je tourne mon téléphone 😱
Le ViewPager est un composant beaucoup utilisé sur Android : il permet d'afficher plusieurs contenus verticaux (des pages) que l'utilisateur peut retrouver en swippant. Dans cet article nous verrons comment corriger un bug très courant lié à la rotation du téléphone.
Le ViewPager fonctionne à l'aide d'un adapter qui fournit une liste de fragments à afficher ainsi que les titres de chaque page pour les afficher éventuellement dans une TabStrip. Voici un exemple d'utilisation :
Voici un exemple tout bête d'adapter :
public class MoviesListsPageAdapter : FragmentPagerAdapter { public MoviesListsPageAdapter (IntPtr javaReference, JniHandleOwnership transfer) : base (javaReference, transfer) { } public MoviesListsPageAdapter (FragmentManager fm) : base (fm) { } public override int Count => 5; private readonly Dictionary<int, Fragment> _fragments = new Dictionary<int, Fragment> { { 0, new MonFragment { MonParam = MediaItemStatus.Watched } }, { 1, new MonFragment { MonParam = MediaItemStatus.Watchlist } }, }; public override Fragment GetItem (int position) => _fragments[position]; public override ICharSequence GetPageTitleFormatted (int position) { switch (position) { default: case 0: return new Java.Lang.String ("mon titre 1"); case 1: return new Java.Lang.String ("mon titre 2"); } } }
J'ai donc deux fragments "MonFragment" identique auquel je donne un paramètre MonParam. Lors du premier affichage cela fonctionne parfaitement mais lorsque je tourne mon téléphone... ça ne marche plus : toutes les pages sont identiques 😱!
La cause du problème est en réalité ce fameux paramètre passé lors de la création du Fragment. Lorsque l'on change l'orientation du téléphone, le fragment n'est pas redemandé à l'adapter mais restauré par le runtime Android. Tout paramètre non sauvegardé est alors perdu et on se retrouve avec un comportement par défaut... Simple à comprendre mais un peu fastidieux à comprendre lorsque l'on ne sait pas d'où cela provient.
Heureusement, la correction est facile, il suffit de sauvegarder ces paramètres dans une surcharge de la méthode OnSaveInstanceState :
public override void OnSaveInstanceState(Bundle outState) { outState.PutInt("MonParam", (int)MonParam); base.OnSaveInstanceState(outState); }
Et de regarder s'il existe ou pas lors de la création de la vue :
public override View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { var ignore = base.OnCreateView (inflater, container, savedInstanceState); if (MediaItemStatus == null && savedInstanceState != null) { MonParam = savedInstanceState.GetInt ("MonParam", "Valeur par défaut"; } }
Si vous voulez aller plus loin, sachez qu'on peut aussi combiner ce composant avec un composant BottomNavigationView (article sur le sujet) pour afficher les différents contenus.
Et voilà : happy coding !
Commentaires