Dot.Blog

C#, XAML, Xamarin, UWP/Android/iOS

Xamarin.Forms : Un bouton à segments

Bien pratique pour permettre une sélection très visuelle le bouton à segments n’existe pas sous tous les OS, mais avec un peu d’astuce et sans code natif on peut le faire en Xamarin.Forms !

Le bouton à segments

C’est un contrôle iOS au départ. Le Segmented Control.

On peut le concevoir en première approche comme une array horizontale de boutons collés les uns aux autres.

image

Rien de bien extravagant mais c’est très pratique… et cela rend un choix bien plus visuel et immédiat qu’un Picker. N’oublions jamais qu’une bonne UI et une UI “lisible”, c’est à dire que moins l’utilisateur n’a besoin de réfléchir mieux c’est. Avec un Picker, il faut penser à taper dessus pour voir les options, certains utilisateurs n’y penseront même pas (débutants, personnes plus âgées et moins aguerries au numérique, etc).

L’avantage du Segmented Control est qu’il rend lisible plusieurs choses essentielles en même temps :

  • La possibilité d’un choix
  • Les valeurs possibles de ce choix

C’est tout bête mais c’est ce qui participe à un design réussi… Et c’est sur iOS que cela existe. Alors on ne s’affole pas, je n’aime pas la pomme croquée pour plein de raisons, et avant de crier au génie il faut se rappeler qu’ils en étaient encore au skeuomorphisme quand Microsoft et Android en étaient déjà à Metro ou Material Design (ou son ancêtre)…

Bref c’est pratique c’est utile et on aimerait bien en avoir l’équivalent sous toutes les plateformes, mais ce n’est pas le cas.

Il faut donc en construire un. Sans code natif c’est plus drôle, tout en Xamarin.Forms (mais graphiquement on verra qu’on peut faire mieux).

Le contrôle

Ne réinventons pas la poudre, Thiago Bertuzzi a déjà créé un tel contrôle. Comme je le disais ce n’est pas parfait, notamment si on veut ajouter un cornerRadius. Au lieu que seules les extrémités soient alors arrondies (comme on peut le voir sur l’image iOS plus haut) chaque bouton de l’ensemble le sera ce qui n’est pas le top visuellement. Je vous déconseille donc les coins arrondis avec cette version, les coins carrés c’est joli aussi, surtout si cela rend l’ensemble plus homogène.

Voici le contrôle en action, j’ai donc choisi un look rectangulaire plutôt que “mal” (ou trop) arrondi :

Segments


Je ne le dirai jamais assez mais pour vos captures écran de ce genre utilisez ScreenToGif qui est très bien fait, qui est open source, et réalisé en WPF ! (https://github.com/NickeManarin/ScreenToGif pour le code source, et ici pour la version compilée : https://www.screentogif.com/)

Comme vous le voyez sur l’animation j’ai créé trois zones avec chacune un texte. Le contrôle fonctionne avec un SelectedIndex qui retourne le bouton actif dans la range 0…nombre de boutons (-1).

Le label que j’ai placé en dessous ne fait qu’un binding au ViewModel pour récupérer le numéro du bouton sélectionné et l’afficher (via un Binding avec StringFormat bien entendu et pas un bricolage de concaténation de chaînes dans le ViewModel…).

Le XAML correspond à l’exemple est le suivant :

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:SegButDemo"
             xmlns:segmentedButton="clr-namespace:Xamarin.Forms.SegmentedButton;assembly=Xamarin.Forms.SegmentedButton"
             x:Class="SegButDemo.MainPage">

    <ContentPage.BindingContext>
        <local:MainViewModel/>
    </ContentPage.BindingContext>

    <StackLayout>
        <segmentedButton:SegmentedButtonControl 
            DefaultColor="SlateGray" 
            SelectedColor="Red" 
            SelectedIndex="{Binding SelectedIndex, Mode=TwoWay}" 
            CornerRadius="0" 
            HeightRequest="20" 
            Margin="8, 8, 8, 0">
            <segmentedButton:SegmentedButtonControl.LabelStyle>
                <Style TargetType="Label">
                    <Setter Property="FontSize" Value="12" />
                    <Setter Property="FontAttributes" Value="Bold" />
                </Style>
            </segmentedButton:SegmentedButtonControl.LabelStyle>
            <segmentedButton:SegmentedButtonControl.SegmentedButtons>
                <segmentedButton:SegmentedButton Title="Aucun" />
                <segmentedButton:SegmentedButton Title="Premier"/>
                <segmentedButton:SegmentedButton Title="Second"/>
            </segmentedButton:SegmentedButtonControl.SegmentedButtons>
        </segmentedButton:SegmentedButtonControl>
        <Label Margin="0,50,0,0" 
               HorizontalOptions="Center"
               Text="{Binding SelectedIndex, StringFormat='Index sélectionné = {0}'}"/>

    </StackLayout>


Je vous fait grâce du ViewModel qui ne contient qu’une seule propriété, SelectedIndex de type int.

Le Package

On trouve ce package dans les nugets, sous le doux nom explicite de Xamarin.Forms.SegmentedButton.

Installez-le dans votre projet Xamarin.Forms sans le placer aussi dans les projets natifs, la construction est un contrôle composite qui ne fait pas usage d’astuces graphiques natives. C’est son avantage, et sa faiblesse aussi comme je le faisais remarquer plus haut.

Sous iOS le contrôle natif sera plus joli mais l’avantage de ce contrôle XF c’est de tourner partout avec un seul et même code central sans aucune intervention dans le code natif de chaque plateforme. Mais grâce à OnPlatform et quelques astuces par exemple on peut fort bien utiliser le contrôle natif sous iOS et le contrôle Xamarin.Forms ailleurs.

Conclusion

Avantages vs inconvénients, c’est le lot de tout développeur, savoir quand s’enquiquiner parfois beaucoup pour une petite différence, savoir quand se contenter d’un truc tout fait qui marche et pouvoir passer plus vite à la suite du projet…

Comme d’habitude c’est à vous de voir, selon les exigences de design du projet et le budget qu’on vous offre pour y arriver ! (c’est souvent là que ça coince… on veut des Ferrari au prix d’une clio…)

En tout cas, bon dev !

Et…

Stay Tuned !

blog comments powered by Disqus