Dot.Blog

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

Adaptive Design et Xamarin.Forms

Ecrire pour le cross-plateforme un seul code commun ne veut pas dire refuser toute adaptation au support ! Par exemple les techniques d’adaptive design pouvant être exploitées au sein d’une App Xamarin.Forms sont nombreuses…

L’adaptive design

Parfois confondu avec le Reactive Design, l’adaptive design vise à adapter l’UI au form factor utilisé, du petit smartphone à l’écran de télé ou de PC.

Le reactive design aurait plutôt une connotation plus technique, à savoir coder de façon à ce que l’App reste réactive, “responsive”’, en toute circonstance. De fait on entend aussi parler de Responsive design.

Hélas comme souvent avec toutes ses expressions et mots nouveaux pas deux personnes s’entendent sur le sens exact. Ainsi on parle parfois d’adaptive design ou de reactive design voire donc de responsive design pour désigner dans les trois cas la capacité d’une UI à s’adapter au form factor.

Ainsi, le lecteur intéressé par le concept et ses différentes mises en œuvre en XAML pourra certainement tirer profit de la lecture des articles suivants qui traitaient de cette question à propos de UWP (du C#/XAML pas très éloigné de celui des Xamarin.Forms). On notera qu’ils datent de 2015 mais comme je traite souvent de sujets bien avant qu’ils n’émergent tout cela reste très moderne ! (Par exemple ma série de 12 vidéos sur le cross-plateforme avec Xamarin et MvvmCross date tout de même de l’été 2013… bien avant que ce sujet ne devienne central et le contenu reste toujours à propos mises à part les différences mineures introduites par le choix du toolbox MVVM) :

UWP étant par nature cross-form-factor, les problèmes soulevés étaient déjà les mêmes que ceux que posent le cross-plateforme et pour les mêmes raisons (différences entre les form factors supportés). L'élargissement des cibles au fil du temps n'a fait que renforcer la nécessité de s'intéresser à ces stratégies. Le passage à MAUI en novembre prochain (2021) ne fera que confirmer ce mouvement.

Donc arrivé ici vous êtes totalement au point sur cette notion d’adaptive design, peu importe le nom exact qu’on lui donne, et ceux qui ne l’étaient pas se sont rués sur les articles en référence et ils sont maintenant au taquet ! On va pouvoir passer à ce qui nous intéresse aujourd’hui …

L’Adaptive Design avec les Xamarin.Forms

Ce ne sera pas un article théorique mais très pratique ! Donc au-delà de l’introduction qui posait le décor nous allons plonger directement dans des cas bien précis de mise en œuvre de l’adaptive design avec les Xamarin.Forms.

S’adapter à la taille des écrans

S’il existe bien un point d’entrée dans le monde concret de l’A.D. c’est bien celui qui concerne la connaissance de la taille de l’écran. C’est même la première chose à prendre en considération. On n’affiche pas tout à fait les mêmes informations en 320x480 (Iphone 3GS) qu’en 5120x2880 (iPad 27” retina 5k)…

Comme il n’existe pas de standard (ah le bon vieux du temps du CGA, EGA ou du VGA ! - références que les plus jeunes auront du mal à saisir...) on trouve même toutes les possibilités intermédiaires ou presque. A cela s’ajoute bien entendu la densité en pixels qui elle aussi modifie totalement la façon d’interpréter la taille écran en pixels.

Il s’avère que les Xamarin.Forms fonctionnent sur un mode proche du pixel effectif de UWP. Par défaut les XF utilisent DIU (Device Independant Unit). Ce qui nous arrange bien puisque nous n’avons donc pas à prendre en compte la densité, les pixels retournés par les XF le font déjà (pour plus d’information voir la documentation “Daling with sizes” sur le site Xamarin – vous noterez que ces aspects de tailles, de pixels et de fontes sont abordés dans mon livre sur les Xamarin.Forms).

Pour s’adapter à la taille de l’écran il faut ainsi obtenir la mesure en pixels, mesure qui sera donnée en DIUs par Xamarin.Forms.

Le moyen le plus simple au sein d’une Page est d’enregistrer un handler pour l’évènement MainPageSizeChanged :


image


C’est un procédé simple et efficace permettant d’adapter la taille d’une image (l’exemple ci-dessus) par exemple. On notera toutefois qu’une interrogation au niveau de chaque page semble assez peu économe, la taille de l’écran ne risque pas de changer en cours d’exécution et obtenir celle-ci une fois pour toute dans App.xaml.cs par exemple peut être plus efficace et surtout plus logique.

Néanmoins il reste à gérer l’orientation de la device, ce qui change la taille écran retournée par l’événement indiqué. Si on veut être sûr de s’adapter à la taille de la device et en même temps aux rotations qui modifient artificiellement celles-ci (la hauteur et la largeur sont simplement inversées) alors l’adaptation au niveau de la Page peut conserver son intérêt.

Répondre aux changements d’orientation

Lorsque la device est tournée du mode paysage au mode portrait, ou inversement, il y a une rotation automatique effectuée par défaut par les Xamarin.Forms. Cela est très pratique puisqu’il n’y a rien à faire. Enfin presque… car il est très rare qu’un écran conçu pour le mode portrait (le plus fréquent sur un smartphone) passe sagement en mode paysage sans que cela ne pose quelques soucis de mise en page !

On peut s’en tenir à l’idée précédente qui consiste à “écouter” les changements de taille de l’écran. Mais on peut aussi détecter directement le changement d’orientation de la device ce qui est parfois plus pertinent. L’un n’interdisant pas l’autre (connaître l’orientation et la taille écran en pixels DIU est plutôt complémentaire).

Les petits futés auront remarqué que sur une device donnée on pouvait d’ailleurs utiliser le même évènement ! Il suffit de regarder si la largeur est plus grande que la hauteur et on sait de façon sûre dans quelle orientation se trouve la device…

image

Dans l’exemple ci-dessus on modifie une variable booléenne quand la taille écran est changée. Selon les proportions hauteur / largeur on peut ainsi créer un flag isPortrait exploitable par le reste de la page.

Le code présenté jusqu’ici doit se comprendre comme du code d’UI, donc il se trouve dans le code-behind de la page concernée et non dans le ViewModel.

Une fois l’orientation connue il est possible depuis le code-behind de modifier la taille et la disposition des éléments à afficher, voire d’en cacher ou montrer certains. Dans l’illustration ci-dessous une partie de l’affichage qui se trouvait au-dessus de l’autre en portrait est plutôt affichée à gauche de cette dernière. Cela change radicalement l’aspect de l’App mais d’une façon si naturelle et évidente que l’utilisateur n’y pensera même pas (alors que sans ce changement, je vous garantis qu’il ronchonnera à juste titre !) :

image

Prendre en compte le type de device

Dans la panoplie de base de l’A.D. il y a la taille de l’écran, son orientation mais aussi le type de la device !

On n’affiche pas les mêmes choses sur l’écran d’un smartphone et sur celui d’une tablette ou d'un Mac, peu importe l’orientation ou la taille en pixels, question de taille physique de l’objet tout simplement et notamment de la distance à laquelle l’objet se trouve des yeux de l’utilisateurs. Un smartphone est tenu très près, une tablette sera posée sur la table comme un écran de portable, un écran de PC sera à 30/50 cm environ, celui d’une télé bien plus loin, etc…

Les Xamarin Forms nous offrent un moyen simple de prendre connaissance du type de la device, par le biais justement de la classe Device et des informations qu’elle retourne.

Il existe quatre types de device qu’on peut tester par exemple dans un switch pour prendre les décisions appropriées :

image


On peut utiliser l’Idiom pour changer la taille des objets, de la fonte, pour modifier la mise en page, voire même pour appeler une page différente au moment de la navigation.

Il est même judicieux de prévoir la substitution d’éléments d’UI par d’autres. Ainsi par exemple une application de dessin proposant un Color Picker pourra gérer différents types de contrôles selon que la device est de type purement tactile (smartphone, phablet, tablette…) ou qu’il s’agit d’une machine disposant d’un outil de pointage plus précis (PC ou Mac et souris)

Utilisation du ContentView en Adaptive Design

Souvent pour s’adapter correctement à la device, sa taille, son orientation... il est nécessaire plutôt que des contorsions en XAML de concevoir son UI par blocs interchangeables. Dans ce cas l’outil le plus pratique est le contrôle ContentView.

En reprenant l’exemple du Color Picker on pourra ainsi concevoir une version simplifiée pour smartphone et une version plus complète pour les écrans plus grands. Charger l’une ou l’autre de ces versions selon le contexte est très simple comme nous l’avons vu dans les sections précédentes.

image


Ici la méthode AddColorPicker (dans le code-behind) instancie une version conçue pour le Touch ou pour la souris selon l’Idiom de la device.

Cette stratégie fonctionne très bien en MVVM puisque ce qui est de la responsabilité de l’UI peut être entièrement traité par le code-behind, le ViewModel n’ayant pas à connaître les aspects visuels.

Les pages personnalisées

En dernier recours il est tout à fait légitime de prévoir des pages totalement différentes selon les contextes. Mieux vaut une page pour le mode portrait et une autre pour le mode paysage qu’une seule page XAML totalement délirante accompagnée d’un code-behind alambiqué et difficile à maintenir. Pensez toujours à la maintenance bien plus qu'à la concision ou la "beauté" de telle ou telle autre astuce... Ce n'est pas un simple conseil c'est une supplique. Vous me remercierez un jour...

MVVM se satisfait très bien de cette situation puisque justement le ViewModel n’a rien à savoir de la View qui l’utilise.

Dans le cas le plus simple il suffit d’instancier le ViewModel en créant la Page, mais dans la réalité en utilisant une toolbox de type Prism par exemple l’implémentation sera légèrement différente. Voici la version simple :

image

Conclusion

De base les Xamarin.Forms nous donnent tout ce qu’il faut pour faire de l’adaptive design. Il suffit juste de s’en servir !

Il existe bien d’autres techniques et d’autres astuces, certains contrôles comme les grilles ou les grilles relatives sont de précieux alliés. Toutefois souvent ces contrôles entraînent une complexification de la logique de la mise en page et rendent l’ensemble moins maintenable que des ContentViews différenciées ou même des pages totalement différenciées.

A vous de bien choisir vos armes !

Stay Tuned !

blog comments powered by Disqus