Dot.Blog

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

Xamarin.Forms et le comportement étrange de ColumnSpan dans les Grids

Parfois on peut perdre des heures sur un détail qu’on pensait régler en deux secondes. Le ColumSpan de l’objet Grid peut être la source d’une telle prise de tête…

Partons d’une simple grille à 2 colonnes

Hors de question de se compliquer la vie, le problème peut être mis en évidence avec quelques lignes de XAML, juste une Grid séparée en deux colonnes plus une Frame qu’on va venir centrer dans l’ensemble. Vraiment du basique de chez basique.

Avec le preview XAML fonctionnel dans Visual Studio 2019 même plus besoin de faire un run…

image

N’oubliez pas de cliquer sur l’image pour obtenir celle à 100%…

Je vous remets le code XAML pour ne rien en louper :

<?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:d="http://xamarin.com/schemas/2014/forms/design"
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
              mc:Ignorable="d"
              x:Class="GridSecret.MainPage">

    <Grid>
         <Grid.ColumnDefinitions>
             <ColumnDefinition Width="*" />
             <ColumnDefinition Width="*" />
         </Grid.ColumnDefinitions>
         <BoxView BackgroundColor="#20D636" Grid.ColumnSpan="2"
                  HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
         <BoxView BackgroundColor="#DF36D6" Grid.Column="1" Grid.ColumnSpan="2"
                  HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
         <Frame BackgroundColor="#00FFF9" WidthRequest="80" HeightRequest="80" Grid.ColumnSpan="2"
                HorizontalOptions="Center" VerticalOptions="Center">
             <Label LineBreakMode="WordWrap" Text="Une boîte centrée" FontAttributes="Bold" FontSize="Large"
                    HorizontalTextAlignment="Center" VerticalOptions="Center" />
         </Frame>
     </Grid>

</ContentPage>

Le problème est évident…

Deux colonnes, dans chacune une BoxView de couleur différente et enfin une jolie Frame centrée. Et pour ce faire nous avons bien entendu pris soin d’indiquer un Grid.ColumnSpan=”2”.

On s’attend à ce que la Frame soit donc bien centrée, pas à la jonction des deux colonnes, c’est joli aussi mais ce n’est pas ce qu’on cherche à faire. Hélas il faut bien le constater ça ne marche pas. La box est à cheval sur les deux zones et non centrée dans la page.

La magie du ColumnSpan…

En réalité est-ce vraiment une erreur de XAML ou bien du développeur ? Difficile à dire, 50/50. Mais les plus attentifs auront remarqué une curiosité, peut-être un reste d’un essai de mise en page (simulé sournoisement ici pour les besoins de la démo…). Oui, regardez bien… Oui vous approchez…

Le second élément de la grille, la seconde BoxView. Elle est bien positionnée en Column=”1”, donc tout est ok, mais elle indique un ColumnSpan=”2”, or il n’y a pas de troisième colonne. Cette indication n’a pas de sens pour un élément placé sur la dernière colonne de la grille.

Cela pourrait s’arrêter là finalement. Mais ce genre de bout de code qui reste en place sans qu’on n’y prenne garde ça arrive, le nier serait stupide. Et c’est là qu’on veut s’appuyer sur un langage ou un environnement qui le prend en compte. Soit en affichant une erreur, le mieux, soit en ignorant le code n’ayant pas de sens.

Mais ici rien de tout cela. Pas d’erreur, pas de prise en compte, et comme c’est le résultat qu’on attend (pour les colonnes en tout cas) on pense que tout va bien.

Jusqu’au moment où le troisième objet, la Frame est ajoutée en colonne 0 avec un Span de 2… Et là, patatras !

On notera qu’en WPF ou UWP cela ne porterait pas à conséquence car tous les débordements de ce genre sont ignorés. Mais pas en Xamarin.Forms…

Un problème de point de vue

Là où d’autres XAML vont ignorer le problème, celui des Xamarin.Forms se conforme aux ordres du chef… Vous êtes sur la 2de colonne d’une grille de 2 colonnes et vous indiquez un Span de 2 colonnes ? Bien chef ! Ça veut dire qu’il y a trois colonnes dont une qui ne se voir pas !

Et c’est ce qui se passe. Le second objet force XAML à créer une troisième colonne en mode star “*”, qui comme elle ne contient rien, ne se voit pas.

De fait les ordres du chef sont respectés ! Le chef ne peut pas être fou et demander un étalement sur une troisième colonne qui n’existe pas... Le chef à toujours raison !

Ainsi la Frame est bien centrée ! Si si. Elle est centrée en fonction de son code, c’est à dire en partant de la colonne 0 avec un Span de 2.

Ça devrait marcher malgré tout noterons les plus perspicaces. Et ils ont raison. C’est qu’en réalité la 3ème colonne en question n’existe pas vraiment comme une colonne, tout en l’étant, sans l’être. Ce sont là les 50% de tort qu’on peut attribuer au XAML des Xamarin.Forms. Une question d’interprétation, de point de vue, mais pas très clair… Cette virtuelle 3ème colonne est un peu comme une segmentation en 2 de la seconde… Peu importe, chercher à comprendre ce qui n’est pas logique fini parfois par devenir tout aussi illogique que le problème lui-même.

Régler le problème

De fait le problème se règle de façon simple, le ColumnSpan du 2d objet n’a aucun intérêt ce sont les 50% d’erreur à la charge du développeur. C’est lui qui fiche le bazar en plus, donc il faut le supprimer. Ce qui donne bien ce qu’on attend :

image

Idem avec les Rows

Bien entendu le code de la Grid étant parfaitement cohérent, le même problème se présente si on joue à ce petit jeu des Span inutiles sur les Rows. Même problème, même solution.

Conclusion

Bug ou pas ? La question est posée, l’équipe Xamarin.Forms y répondra un jour certainement. Peut-être est-ce déjà fait (je vous rappelle qu’il y a un décalage de plusieurs mois entre la sortie de mes articles du second semestre 2020 et leur écriture en juillet…).

En attendant, vérifiez bien la taille de vos Span dans les grilles… Car toute une mise en page peut tomber à l’eau sans raison apparente à cause de cela !

A bon entendeur ….

Stay Tuned !

blog comments powered by Disqus