Loupe

Xamarin: Faire scroller automatiquement une ListView lors de l'appui sur un onglet

Il est très fréquent de voir, dans des applications mobiles, des ListViews qui, lorsque l'on appuie sur l'onglet qui les contient, remontent automatiquement en haut de la liste.

C'est par exemple le cas dans l'application Outlook, sur iOS et Android. Je trouve cette fonctionnalité très pratique car elle évite à l'utilisateur de devoir scroller à nouveau dans le sens inverse pour pouvoir revenir au début. Je me suis demandé comment faire la même chose dans une application Android (avec Xamarin.Forms) et je me propose de vous partager ma solution.

La première chose à faire est de mettre en place sa page avec ses onglets:

<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
            xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
            xmlns:local="clr-namespace:DemoListView"
            x:Class="DemoListView.MainTabbedPage"
            android:TabbedPage.ToolbarPlacement="Bottom">
    <local:MainPage Title="Tab1" />
</TabbedPage>

Vous noterez l'utilisation de "android:TabbedPage.ToolbarPlacement="Bottom"", disponible depuis Xamarin.Forms 3.0 et qui permet de positionner les onglets sur le bas de l'écran (habituellement, sous Android, ils sont en haut).

A présent, nous allons utiliser un renderer pour venir agrémenter notre page d'onglets avec cette nouvelle fonctionnalité :

[assembly: ExportRenderer(typeof(MainTabbedPage), typeof(MainPageRenderer))]
namespace DemoListView.Droid
{
    public class MainPageRenderer : TabbedPageRenderer, BottomNavigationView.IOnNavigationItemSelectedListener 
    {
        public MainPageRenderer(Context context) 
            : base(context)
        {
        }

        bool BottomNavigationView.IOnNavigationItemSelectedListener.OnNavigationItemSelected(IMenuItem item)
        {
            if (item.TitleFormatted.ToString() == Element.CurrentPage.Title)
            {
                if(Element.CurrentPage is ContentPage contentPage)
                {
                    if(contentPage.Content is Layout<Xamarin.Forms.View> layout)
                    {
                        var listView = layout.Children.OfType<Xamarin.Forms.ListView>().FirstOrDefault();
                        if(listView != null)
                        {
                            listView.ScrollTo((listView.ItemsSource as IEnumerable<object>).First(), ScrollToPosition.Start, true);
                        }
                    }
                }
            }

            return true;
        }
    }
}

La première chose à remarquer est que notre classe implémente BottomNavigationView.IOnNavigationItemSelectedListener et non pas TabLayout.IOnTabSelectedListener comme on peut le voir sur Internet. La raison est simple: lorsque les onglets sont positionnés en bas, c'est une BottomNavigationView qui est utilisé par Android pour faire le rendu, et non un TabLayout. Cela peut paraitre logique, mais cela m'a fait perdre quelques heures d'investigation!

Ensuite, le reste du code est assez trivial: on s'assure que l'onglet sur lequel l'utilisateur a cliqué est bien celui de la page courante, on récupère la ListView qui est à l'intérieur et on s'assure de scroller sur le 1er élément. Le résultat, en vidéo, est sans appel:

Il y a sans doute mieux/plus propre en termes de code, cet article relève plus du POC que du code de production. Mais, dans tous les cas, cela vous donne un bon aperçu !

 

Happy coding! :)

Ces billets pourraient aussi vous intéresser

Vous nous direz ?!

Commentaires

comments powered by Disqus