Dot.Blog

C#, XAML, WinUI, WPF, Android, MAUI, IoT, IA, ChatGPT, Prompt Engineering

MAUI L’AbsoluteLayout pour quoi faire ?

Parmi les nombreuses stratégies de mise en page offertes l’AbsoluteLayout reste trop souvent  ignorée. Pourquoi ? Et, le mérite-t-elle ? C’est ce que nous allons tenter de voir dans ce billet..

AbsoluteLayout, pour quoi faire ?

Alors autant le dire d’emblée je ne dispose pas de statistiques officielles et mondiales sur l’utilisation des contrôles de mise en page sous MAUI… Je ne peux donc me fier qu’à mon expérience, qui même large n’offre qu’un panel qui n’a que peu de chance d’être scientifiquement représentatif. Mais bon, c’est un avis d’expert, et beaucoup de nos décisions et de nos prévisions en tout domaine se font sur ce type d’avis qui est souvent meilleur que celui de monsieur tout-le-monde au café du coin. Cela reste donc à prendre avec recul mais c’est mieux que pas d’avis du tout ou l’avis de quelqu’un qui ne connaît pas le domaine.

Cela étant posé, ma constatation au travers de mes audits, des projets pour lesquels j’interviens en Conseil ou en développement, c’est que l’AbsoluteLayout est mal aimé, donc peu utilisé.

Pourquoi ?

De deux choses l’une : soit c’est un contrôle sans intérêt et ceci explique donc cela, soit c’est un contrôle très intéressant mais mal compris (peut-être parce qu'on l'a trop décrit comme une sorte de Canvas WPF ?), ceci expliquant aussi cela.

Soyons francs, techniquement l’AbsoluteLayout au premier contact n’est pas une merveille sur laquelle on a spontanément envie d’écrire un roman fleuve… C’est vrai. Mais ce conteneur se montre capable de choses tout à fait utiles notamment dans le cadre de l’Adaptive Design par exemple.

Alors si ce contrôle est utile et peu utilisé et en nous référant à l’alternative posée plus haut c’est qu’en toute logique il est mal compris.

Cette incompréhension je la crois venir de deux origines différentes, la première est le nom AbsoluteLayout qui fait penser comme je le disais à une sorte de Canvas XAML (WPF) c’est à dire un objet où les coordonnées des enfants visuels s’expriment en Pixels donc de façon absolue. Ce n’est pas faux en plus, c’est l’une des utilisations de l’AbsoluteLayout. Or tout le monde le sait, on vous l’a seriné assez souvent, avec les différents form factors existants aujourd’hui il ne faut absolut(ment) pas utiliser ce type de conteneur visuel ! Il faut faire de l’Adaptive Design, du Responsive UI, du truc hype hypra cool de djeuns. Et pour une fois ce ne sont pas des âneries juste pour faire une mode. C’est fondé et justifié.

Mais l’AbsoluteLayout est bien plus malin qu’un Canvas WPF, il accepte un paramétrage plus fin permettant de rendre une, plusieurs ou toutes les coordonnées et tailles relatives et non plus “Absolute” ! il porte donc très mal son nom, ce qui égare encore plus le passant qui zappe sur les contrôles MAUI...

Et c’est ce second aspect qui aurait pu sauver de l’anonymat l’AbsoluteLayout qui l’enfonce encore plus, car cet aspect semble confus, et ce qui n’est pas clair ne donne pas envie de chercher plus loin.

Et voici comment un bon contrôle très utile peut se trouver sous-utilisé pour des raisons qui finalement n’ont rien de techniques.

Il est temps de réhabiliter le soldat AbsoluteLayout, et s’il en fallait un assez courageux pour une telle mission au demeurant pas très réjouissante, c’est bien votre serviteur !

Donc je m’y colle…

Mais vous allez voir ce n’est pas non plus une punition hein ! Vous allez découvrir des choses étonnantes et bien pratiques si vous ne connaissiez pas l’AbsoluteLayout et ça c’est réjouissant !

Propriétés et Syntaxe de base

L’AbsoluteLayout est un contrôle visuelle, une “vue” au sens Android, mais je préfère “contrôle visuel” dans une terminologie plutôt XAML surtout que MAUI ne s’appliquent pas qu’à Android mais aussi à iOS, UWP, Mac etc.

C’est une surface, un support on dit plutôt un “conteneur visuel”.

On crée une instance en XAML de la façon la plus traditionnelle c’est à dire par une balise ouvrante. Beaucoup d’éléments XAML peuvent avoir une balise fermante “intégrée” et simplifiée en ajoutant “/>” en fin de ligne, c'est du XML après tout. S’agissant ici d’un conteneur il faudra bien entendu écrire les balises enfants à l’intérieur, donc on trouvera généralement deux balises distinctes, l’une d’ouverture <AbsoluteLayout> et l’autre de fermeture </AbsoluteLayout> quelque part plus bas dans le code XAML.

Les propriétés offertes sont relativement limitées (outre le “pot commun” des contrôles visuels de MAUI). Notamment on trouve une BackgroundColor dont le nom devrait suffire à expliquer son utilité.

En utilisant les propriétés communes on peut bien entendu fixer sa taille, sa position, son mode de dilatation (Expand ou pas par exemple), son centrage horizontal et toutes ces choses habituelles qui ne sont pas réservées à l’AbsoluteLayout.

Propriétés Attachées

Là où l’AbsoluteLayout se distingue d’autres contrôles c’est qu’il propose deux propriétés attachées très importantes. C’est le cas de beaucoup de conteneurs comme la Grid qui offre les propriétés Row et Column à ses enfants visuels. L’AbsoluteLayout offre, lui, les propriétés LayoutBounds et LayoutFlags.

Et c’est de là que vient un peu la complexité ou la confusion avec un simple Canvas à la WPF. Les fameux flags vont permettre de transformer ce qui ne serait en effet qu’un simple Canvas en quelque chose de beaucoup plus puissants et plus “moderne” donc utile.

Les flags vont modifier la façon dans la propriété LayoutBounds est interprétée. Et j’ai remarqué qu’à chaque fois qu’un contrôle avait ce type de comportement c’était confusant et que beaucoup de gens évitaient de s’en servir. Ici c’est vraiment bête de se priver des services de AbsoluteLayout à cause de cela car ce n’est pas si compliqué. Mais, je l'avoue, cet espèce de double effet kiss cool avec des flags qui modifient la façon d'interpréter certaines propriétés, ce n'est pas non plus mon truc. j'aime bien les choses carrées et là c'est un peu déroutant. Mais ce n'est qu'une question de pratique. Celui qui code du XAML du matin au soir sera au point en deux jours.

Les modes de fonctionnement

Si on ne dit rien, si on ne précise rien dans le code, par défaut l’AbsoluteLayout est en effet un Canvas WPF. De fait les LayoutBounds sont exprimées en pixels sur 4 nombres. Par exemple “0,0,1,1” signifiera Position X = 0, Position Y = 0, Largeur = 1 Pixel, Hauteur = 1 Pixel, dans cet ordre là bien précis.

Placer un carré de 10 pixels de côté à 150 pixels du haut et 50 pixels de la gauche de l’écran s’écrira donc “50,150,10,10”

Mais rappelez-vous, ce sont des propriétés attachées.. on parle donc ici des LayoutBounds exprimées dans un contrôle visuel enfant de l’AbsoluteLayout …

 Il est clair que ce mode de type Canvas WPF ne sert plus à grand chose aujourd’hui. Il y tant de machines différentes à supporter avec le même code, des machines ayant des résolutions et des  tailles si différentes que travailler en pixel est tout bonnement impossible ou presque (on peut utiliser ce mode pour définir un contrôle personnalisé qui aurait un aspect figé par exemple, ou bien pour faire un jeu en déplaçant des objets facilement par des coordonnées x,y ...).

Mais alors pourquoi ce contrôle existe-t-il ?

Mais parce que tout cela n’est qu’un mode de base qui va pouvoir se moduler ! Si vous ne modulez pas, ça ne sert à rien ou presque on est d’accord, mais ce conteneur ne s’utilise qu’en modulant le système de coordonnées.

Et ça veut dire quoi “moduler le système de coordonnées”. Absolument rien mais ça fait bien non ? En réalité je veux dire par là qu’il va falloir utiliser d’autres propriétés de l’AbsoluteLayout qui vont modifier la façon dont les coordonnées sont interprétées. Moduler le système de coordonnées donc. Finalement ça avait un sens…

Proportions au lieu de pixels

L’astuce est simple mais plein de potentiel ! Dans les fameuses propriétés attachées que l’AbsoluteLayout propose on trouvait LayoutFlags. Il y a un “s” donc plusieurs flags. Et ces flags que font-ils à quoi servent-ils ? 

Dans LayoutBounds on rangeait les propriété X, Y, Width et Height dans cet ordre. Avec les LayoutFlags on va tout simplement pouvoir accrocher, dans le même ordre, un flag pour chaque coordonnée ce qui va indiquer à l’AbsoluteLayout comment interpréter la valeur.

Deux possibilités : En Absolu ou en Proportion.

Et vous avez le pourquoi du nom qui est crétin, AbsoluteLayout aurait du s’appeler ProportionalLayout ça aurait été plus engageant, sachant que le mode fixe (Absolu) n’est pas le plus intéressant ni le plus utilisé…

Même si toutes les combinaisons sont possibles, pour faire simple et efficace on va dire que principalement on applique le principe absolu ou proportionnel soit aux coordonnées pures (X,Y), soit au coordonnées de taille (Width et Height). On peut le faire pour toutes, si on ne le fait pour aucune… oui j’en vois qui suit… on revient au mode Canvas WPF… Intérêt nul donc (ou presque).

Regardons alors les façons plus intelligentes d’utiliser le contrôle et ses variantes. Si nous décidons que X et Y sont proportionnelles mais que la taille l'est aussi, tout devient propertionnel. Mais proportionnel à quoi ? A la taille de l'AbsoluteLayout tout simplement. Peu importe cette taille qui elle est fixée dans la balise de ce conteneur et conditionnée aussi par ce dans quoi il se trouve.

Dans ce mode particulier les valeurs de LayoutBounds s’expriment sous la forme d’un nombre décimal allant de 0 à 1. On peut voir cela comme un pourcentage. 0% à 100% si vous multipliez par 100 pour avoir des pourcentages “grand public”.

Comme c’est une utilisation courante il existe des raccourcis pour les flags. Si tous les flags sont proportionnels on indique juste LayoutFlags=”All”.

De même on peut vouloir une taille d’objet fixe mais un placement proportionnel (ou l’inverse) dans ce cas on peut utiliser d’autres raccourcis comme “PositionPropertional” (à la place de XProportional, XProportional) ou “SizeProportional” (à la place de WidthProportional,HeightProportional).

Comme vous le voyez ce n’est pas bien sorcier on est soit en mode Canvas WPF soit en mode proportionnel. La seule subtilité c’est qu’on peut choisir ce mode indépendamment pour chaque propriétés de LayoutBounds ou bien le faire soit sur la partie coordonnées soit sur la partie taille.

Quelques utilisations ?

Je n’arrête pas de vous le dire donc je pense que c’est bien compris : l’adaptive design ou le reactive design, bref des UI complexes qui s’adaptent aux conditions différentes d’affichage sans réclamer aucun code C# pour le faire. Un truc pour les pros du design XAML donc. Mais c’est un métier, ça s’apprend. L’AbsoluteLayout vous met le pied à l’étrier en quelque sorte…

On pouvait aussi utiliser dans cet esprit un autre contrôle, le RelativeLayout, celui-là est un peu plus vicieux et difficile à maitriser. Hérité des Xamarin.Forms il ne se trouve plus que dans le paquet de compatibilité d'ailleurs et n'est plus du tout conseillé dans MAUI, comme quoi quand c'est trop chelou ça ne reste pas... Donc notre bizarre AbsoluteLayout est utile puisqu'il est toujours là !

Dans le jargon du design je vous ai parlé de reactive design, de Complex UI, d’adaptive design, mais il y a aussi le Responsive Design ! Tout cela se vaut même si certains attachent des sens différents ou des nuances. Rappelez-vous juste que le but du jeu est de faire des UI capables de s’adapter à plein de circonstances, de résolutions, de tailles d’écran, de format paysage ou portrait, etc, le tout “automatiquement” juste en XAML sans code C#. Dans le type de cette capture.

Le  code de cette fiche utilisateur 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:AbsoluteLayoutSample" 
             x:Class="AbsoluteLayoutSample.AbsoluteLayoutSamplePage">
    
    <AbsoluteLayout Padding="20"  VerticalOptions="CenterAndExpand">
         <Entry  AbsoluteLayout.LayoutBounds="0,40,1,40" AbsoluteLayout.LayoutFlags="XProportional,WidthProportional" Placeholder="UserName" HorizontalOptions="FillAndExpand"/>
         <Entry AbsoluteLayout.LayoutBounds="0,85,1,40" AbsoluteLayout.LayoutFlags="XProportional,WidthProportional" Placeholder="Password"  HorizontalOptions="FillAndExpand"/>
         <Entry AbsoluteLayout.LayoutBounds="0,130,0.5,40" AbsoluteLayout.LayoutFlags="XProportional,WidthProportional" Placeholder="NickName"  HorizontalOptions="FillAndExpand"/>
         <Entry  AbsoluteLayout.LayoutBounds="1,130,0.5,40" AbsoluteLayout.LayoutFlags="XProportional,WidthProportional" Placeholder="Phone"  HorizontalOptions="FillAndExpand"/>
         <Button  AbsoluteLayout.LayoutBounds="0,180,1,40" AbsoluteLayout.LayoutFlags="XProportional,WidthProportional"  HorizontalOptions="FillAndExpand" Text="Register" TextColor="White" BackgroundColor="Black"/>
     </AbsoluteLayout>
</ContentPage>

Dans ce code on voit que la taille est proportionelle mais que seule la coordonnées X l'est aussi, Y est donc fixe (et contraint les lignes à un espacement précis). 

On peut aussi utiliser l’AbsoluteLayout pour faire des choses “complexes”, le fameux “Complex UI”. A quoi cela ressemble ? Et bien par exemple faire une portée musicale avec des notes dessus si vous y avez réfléchi ce n’est pas forcément une sinécure … Alors que faire ça :

…Se réalise avec le code suivant :

<?xml version="1.0" encoding="utf-8"?>
<ContentPage ...>
    
    <AbsoluteLayout Padding="20"  VerticalOptions="CenterAndExpand">
         <BoxView  AbsoluteLayout.LayoutBounds="0,40,1,1" AbsoluteLayout.LayoutFlags="XProportional,WidthProportional" BackgroundColor="DarkGray"/>
         <BoxView  AbsoluteLayout.LayoutBounds="0,50,1,1" AbsoluteLayout.LayoutFlags="XProportional,WidthProportional" BackgroundColor="DarkGray"/>
         <BoxView  AbsoluteLayout.LayoutBounds="0,60,1,1" AbsoluteLayout.LayoutFlags="XProportional,WidthProportional" BackgroundColor="DarkGray"/>
         <BoxView  AbsoluteLayout.LayoutBounds="0,70,1,1" AbsoluteLayout.LayoutFlags="XProportional,WidthProportional" BackgroundColor="DarkGray"/>
         <BoxView  AbsoluteLayout.LayoutBounds="0,80,1,1" AbsoluteLayout.LayoutFlags="XProportional,WidthProportional" BackgroundColor="DarkGray"/>
         <Image Source="solClave" Aspect="AspectFit" AbsoluteLayout.LayoutBounds="0,30,60,60" AbsoluteLayout.LayoutFlags="XProportional"/>
         <Label Text="4&#10;4" AbsoluteLayout.LayoutBounds="50,40,50,50" />
         <BoxView AbsoluteLayout.LayoutBounds="60,97,20,2" BackgroundColor="DarkGray"/>
         <Image Source="note.png" Aspect="AspectFit" AbsoluteLayout.LayoutBounds="60,80,20,20" x:Name="C"/>
         <Image Source="note.png" Aspect="AspectFit" AbsoluteLayout.LayoutBounds="80,70,20,20" x:Name="D"/>
         <Image Source="note.png" Aspect="AspectFit" AbsoluteLayout.LayoutBounds="100,65,20,20" x:Name="E"/>
         <Image Source="note.png" Aspect="AspectFit" AbsoluteLayout.LayoutBounds="120,60,20,20" x:Name="F"/>
         <Image Source="note.png" Aspect="AspectFit" AbsoluteLayout.LayoutBounds="140,55,20,20" x:Name="G"/>
         <Image Source="note.png" Aspect="AspectFit" AbsoluteLayout.LayoutBounds="160,50,20,20" x:Name="A"/>
         <Image Source="note.png" Aspect="AspectFit" AbsoluteLayout.LayoutBounds="180,45,20,20" x:Name="B"/>
         <Image Source="note.png" Aspect="AspectFit" AbsoluteLayout.LayoutBounds="200,50,20,20" x:Name="A2"/>
         <Image Source="note.png" Aspect="AspectFit" AbsoluteLayout.LayoutBounds="220,55,20,20" x:Name="G2"/>
         <Image Source="note.png" Aspect="AspectFit" AbsoluteLayout.LayoutBounds="240,60,20,20" x:Name="F2"/>
         <Image Source="note.png" Aspect="AspectFit" AbsoluteLayout.LayoutBounds="260,65,20,20" x:Name="E2"/>
         <Image Source="note.png" Aspect="AspectFit" AbsoluteLayout.LayoutBounds="280,70,20,20" x:Name="D2"/>
         <BoxView AbsoluteLayout.LayoutBounds="300,97,20,2" BackgroundColor="DarkGray"/>
         <Image Source="note.png" Aspect="AspectFit" AbsoluteLayout.LayoutBounds="300,80,20,20" x:Name="C2"/>
     </AbsoluteLayout>
</ContentPage>

Etonnant non ?

On peut même s’en servir pour superposer des éléments et créer des montages visuels, bref c’est riche, et ça mérite de s’y intéresser !

Conclusion

Qui aurait dit que derrière l’AbsoluteLayout se cachait tant de puissance pour si peu de complexité une fois le principe compris ? Dessiner une portée musicale est un exercice de style délicat même en XAML WPF, et pourtant là on peut s’en sortir assez facilement. C’est un bon exemple de complexité totalement gérée en XAML sans une seule goute de code C# !

Mail aimé, sous utilisé, c’est ce que j’ai remarqué, mais peut-être que cette modeste contribution pourra vous inciter à dépasser les apparences et à adopter l’AbsoluteLayout pour la création de vos designs !

Et pour en savoir plus n'oubliez jamais la documentation officielle, elle contient tous les détails à jour.

Stay Tuned !

Soyez le premier à noter cet article

  • Currently .0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Faites des heureux, PARTAGEZ l'article !