Dot.Blog

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

Cross-plateforme : la mise en page sous Android (de Xaml à Xml).

[new:30/09/2013]Après avoir abordé de nombreux exemples techniques de programmation sous toutes les plateformes principales (WinRT, Windows Phone 8, WPF, Android…) il est nécessaire d’en connaitre un peu plus sur chacune pour développer de vraies applications. Dot.Blog regorge d’informations sur Xaml alors ajoutons quelques informations essentielles sur Android en les rapprochant de nos connaissances Xaml…

Chapitres antérieurs

Depuis plus d’un an Dot.Blog vous prépare psychologiquement autant que techniquement à la situation présente… Un monde dans lequel le développement devient cross-plateforme car plus aucun éditeur d’OS n’est en mesure de porter à lui-seul 100% du marché et que le partage de ce dernier est beaucoup plus équilibré que par le passé où la domination quasi monopolistique de Microsoft nous avait mis à l’abri des affres du choix... On a beaucoup critiqué Microsoft sur cette période, on a même fait des procès à Microsoft pour sanctionner ses pratiques anti-concurrentielles. Mais comme toute dictature il y avait un avantage énorme : la stabilité, et la stabilité c’est bon pour les affaires... On le voit politiquement là où les dictatures tombent c’est le chaos bien plus qu’une riante démocratie qui s’installe… Si la Liberté des Hommes ne se discute pas et qu’on peut accepter d’en payer le prix fort, dans notre humble domaine le chaos est plutôt une mauvaise chose, une bonne hégémonie simplifie tout et facilite le business. Mais ces temps sont révolus comme je vous y prépare de longue date (lire le “Big Shift” billet de 2011…). Mais je ne fais pas qu’alerter longtemps à l’avance, cette avance je l’utilise pour vous former aux parades qui vous protègeront de ces changements. La parade contre le chaos actuel s’appelle le cross-plateforme.

Le sujet a été traité des dizaines de fois mais quelques séries méritent votre attention si jamais vous les avez loupées :

Stratégie de développement cross-plateforme

Série en 4 parties :

Cross-plateforme : L’OS Android

Série en 5 parties abordant les spécificités principales d’Android :

8h de video en 12 volets MvvmCross sous WinRT / WPF / Windows Phone 8 et Android

Sans oublier bien entendu cette série exceptionnelle de 12 vidéos pour un total de 8h en HD sur le développement cross-plateforme :

L’IoC clé de voute du Cross-plateforme

l’IoC avec MvvmCross, de WinRT à Android en passant par Windows Phone, PDF a télécharger.

La stratégie de mise en page sous Android

J’ai déjà parlé de mise en page sous Android mais depuis la série de vidéos (voir liens ci-dessus) je me suis rendu compte que finalement, dès lors qu’on approche le cross-plateforme avec la méthode que je décris le seul véritable problème qui se pose est celui de la mise en page sous cet OS. En effet, la stratégie que je vous propose de suivre déporte toute la complexité dans un projet noyau qui n’est que du C#. Les projets d’UI sont rudimentaires et le plus souvent ne contiennent aucun code, en dehors de la mise en page.

Travailler sous WinRT, WPF, Silverlight, Windows Phone, tout cela est facile pour ceux qui suivent Dot.Blog depuis longtemps puisque C# et Xaml en sont le sujet de prédilection. Créer un logiciel cross-plateforme ne pose donc aucun souci pour le noyau ni pour la création des projets d’UI en OS Microsoft. La seule difficulté consiste donc à réussir des mises en page sous Android (et même iOS que je n’aborde pas mais qui peut intéresser des lecteurs).

Dès lors, la seule chose cruciale à apprendre pour coder un premier projet cross-plateforme quand on suit ma méthode c’est d’être capable de faire la mise en page de l’application sous Android car cet OS est aujourd’hui aux unités mobiles ce que Microsoft a été aux PC pendant les 25 dernières années. Tout simplement.

D’où l’idée de ce billet qui regroupe les principales informations de base à propos de la stratégie de mise en page sous cet OS. Avec ces bases vous serez à même de comprendre l’essentiel pour vous lancer et mieux comprendre les informations complémentaires que vous pourrez glaner sur le Web. En tout cas c’est l’objectif !

XML Based

La première chose à savoir c’est que la mise en page d’une application Android passe par un langage de définition très proche de Xaml dans son formalisme puisqu’il s’agit d’un fichier XML. On y retrouve ainsi des balises avec des attributs et des contenus qui forme le plus souvent des arborescences décrivant la structure du document.

La grande différence avec Xaml est la nature du système d’affichage. Sous Xaml nous travaillons (et c’est unique en informatique, SVG n’étant pas à la hauteur) dans un mode totalement vectoriel autorisant aussi bien la présence de composants visuels complexes que de dessins en courbes de Béziers. Le système des templates, des styles, du bindind font de Xaml l’arme absolue de la mise en page et, peut-être par manque d’imagination, je n’arrive pas à concevoir ce qui pourrait être inventé de très différent et de beaucoup mieux.

Donc sous Android c’est très proche, formellement, mais fondamentalement différent sur le fond. On se rapproche beaucoup plus d’une mise en page de type HTML que de Xaml avec des bitmaps découpés ou retaillés. Toutefois la notion de contrôles sous Xaml se retrouve dans celle de “widget” ou de “view” sous Android et la façon d’imbriquer des conteneurs est proche de la stratégie XAML (grille, panels etc).

Java-Based

Android est un OS qui a choisi d’utiliser nativement un Java (qui normalement ne doit pas s’appeler comme ça suite à un procès lancé et gagné par Oracle). Pour le développeur C# c’est à 90% gagné puisque la syntaxe de C# est plus qu’inspirée par celle de Java. Mais c’est encore mieux quand on utilise la stratégie de développement cross-plateforme que je vous propose puisqu’elle passe par Xamarin qui nous offre un C# natif Android d’un niveau excellent (intégrant Linq, les expression lambda, await/async…).

Toutefois le fait que le langage natif soit du Java et non un C obscure et illisible, cela permet facilement de lire les documentations qu’on trouve sur le Web et de transposer parfois par un simple copie/coller les exemples qu’on peut voir ici et là …. Très pratique donc ! Dans la pratique Android est bien plus sympathique que iOS.

Les attributs de mise en page

Chaque classe de Layout possède une classe interne appelée LayoutParams qui définit les paramètres XML généraux de mise en page. Dans un fichier XML de mise en page ce sont des attributs qu’on retrouve sous la forme sous des noms qui commencent systématiquement par android:layout_xxxx et qui traitent le plus fréquemment de la taille de l’objet ou de ses marges.

Voici un exemple de mise en page minimaliste XML Android :

image

Les classes de layout définissent bien entendu d’autres attributs en relation directe ou non avec leur mise en page, leur forme, leur positionnement, etc.

Dans le code exemple ci-dessus on peut voir la description d’une page très simple qui s’ouvre sur une balise LinearLayout (l’équivalent d’un StackPanel XAML) contenant un TextView (un TextBlock XAML) et un Button (devinez !).

Chaque objet d’UI possède des attributs, dont la poignée de paramètres généraux évoqués plus haut comme android;layout_width ou android:layout_height (hauteur et largeur de l’objet).

Les autres attributs sont donc spécifiques à la classe (comme text pour le TextView), c’est attributs ne commencent pas par “layout_” puisqu’ils ne concernent pas directement la mise en page.

Les attributs utilisés couramment

La Taille (Size)

android:layout_height et android:layout_width permettent de fixer la taille de l’objet (hauteur et largeur).

Les valeurs de tailles, marges et autres dimensions s’expriment de plusieurs façons sous Android. Soit en pouce (in pou inch) en millimètres (mm) ou d’autres unités plus pratiques pour gérer les différentes résolutions et densités d’écran qu’on trouve sous Android.

Le système d’unités

  Ecrans basse résolution Ecrans haute résolution même taille
Taille physique

1,5 pouce

1,5 pouce

Points par pouces (dpi)

160

240

Pixels (largeur*dpi)

240

360

Densité (base = 160)

1,0

1,5

Density Independant Pixels (dip ou dp ou dps)

240

240

Scale Independant pixels (sip ou sp)

dépend du paramétrage de la taille de fonte par le user

Idem

Le tableau ci-dessus montre les relations entre les différentes unités utilisées couramment pour les mises en page. Si on peut utiliser des tailles en pixels en millimètres ou en pouces ce ne sont bien entendu pas des unités réellement utilisées car elles offrent un rendu bien trop différents selon les tailles réelles des écrans et surtout de leurs densités.

On préfère utiliser les Density Independant Pixels, pixels indépendant de la densité, qui permettent des mises en page ayant le même aspect quelque que soit la résolution de la machine. Les chiffres s’expriment alors suivi du suffixe “dp”.

Les Scale independant Pixels sont moins utilisés mais peuvent être très utiles dans une stratégie se basant sur le réglage de la taille de fonte qu’a choisi l’utilisateur. On s’adapte alors non plus à la densité de l’écran mais à la taille de cette fonte. Un utilisateur ayant une mauvaise vision et réglant son appareil en mode fonte de grande taille verra alors l’application qui utilise des unités “sp” suivre le même facteur de grossissement, ce qui est indispensable si on cible certains clients/utilisateurs.

Les “dp” restent toutefois les plus utilisées. Dans le tableau ci-dessus on montre le rapport entre toutes ces unités en prenant en exemple deux écrans, l’un de faible densité, l’autre ayant une haute densité. On se place dans le cas d’un objet qui mesure 1,5 pouce (taille physique) qui sera affiché à l’identique sur les deux écrans. Sa taille physique sera donc de 1,5 pouce dans les deux cas.

Le premier écran a une densité de 160 dpi (dots per inch, points par pouce), le second 240 dpi. On est loin encore des résolutions de type Retina sur le haut de gamme Apple ou Samsung mais le tableau pourrait être étendu à l’infini, les deux exemples suffisent à comprendre le principe.

Sur le premier écran l’objet sera dessiné en utilisant 240 pixels, sur le second il faudra 360 pixels pour remplir le même pouce et demi.

Android pose comme facteur de densité la valeur de 1.0 pour le premier cas (160 dpi). L’écran de plus haute densité possède donc un facteur de 1,5 ici.

Pour couvrir le pouce et demi de notre objet, si on utilise les DIP il faudra ainsi “240dp” pour dessiner l’objet. La magie s’opère quand on regarde la taille pour l’écran haute densité: “240dp” aussi… Android se charge alors de traduire les “dp” en pixels réels pour que l’objet mesure toujours 1,5 pouce.

En mode SIP on voit qu’il est difficile ici de prévoir la taille puisque celle-ci dépend de la taille de la fonte choisie par l’utilisateur. Ce mode, comme je le disais plus haut, n’est pas le plus utilisé.

On se rappellera ainsi que les mises en pages Android se font en utilisant principalement les DIP, des mesures notées “XXXdp”.

Android possédait un canvas similaire à celui de Xaml avec positionnement absolu mais il est deprecated. S’il ne l’est pas en Xaml c’est un conteneur qu’on utilise très peu pour les mêmes raisons de rigidité. Sous WPF ou Silverlight, et même WinRT, on préfère utiliser des Grid ou des StackPanel, et là on retrouve des équivalents presque copie-conforme (TableLayout, LinearLayout…). Les stratégies de placement se ressemblent donc beaucoup.

Les valeurs spéciales

Il existe quelques valeurs “spéciales” pour les tailles. Elles sont très souvent utilisées car elles permettent d’éviter de donner des mesures précises et donc autorise une plus grande souplesse d’adaptation aux différents form factors :

match_parent : remplir totalement l’espace du conteneur parent (moins le padding). Renommé dans les dernières versions d’Android (s’appelait avant fill_parent).

wrap_content : utiliser la taille “naturelle” de l’objet (plus le padding). Par exemple un TextView occupera la taille nécessaire à celle du texte qu’il contient.

On peut aussi fixer une taille à zéro et utiliser l’attribut android:layout_weight qui permet de fixer une dimension de façon proportionnelle, un peu comme les lignes ou colonnes dans un Grid Xaml en utilisant la notation “étoile”.

L’alignement

Autre attribut de base pour mettre en page un objet, outre sa taille, son alignement est essentiel.

On utilise android:layout_gravity pour déterminer comment l’objet est aligné dans son conteneur.

android:gravity ne doit pas être confondu avec le précédent attribut, ici il s’agit de fixer comment le texte ou les composants dans l’objet sont alignés.

Les valeurs possibles pour ces attributs sont de type : top, bottom, left, right, center_vertical, center_horizontal, center, fill_vertical, fill_horizontal, fill, clip_vertical,clip_horizontal.

Selon le cas les valeurs peuvent être associées avec un symbole “pipe” | (Alt-124).

Les marges

Encore une fois très proche de la notion de même nom sous Xaml, les marges des widgets Android servent exactement à la même chose : mettre un espace autour de l’objet. Sur un côté, deux côté, trois ou les quatre.

Le système d’unité utilisé est le même que pour la hauteur et la largeur.

android:layout_marginBottom, android:layout_marginTop, android:layout_marginLeft et android:layout_marginRight s’utilisent selon les besoins, ensemble ou séparément.

Les unités négatives sont autorisées (par exemple “-12.5dp”).

Le padding

Encore une notion courante qui ne posera pas de problème aux utilisateur de Xaml. Si la marge est l’espace qui se trouve autour du widget, le padding est celui qui se trouve entre sa bordure extérieure (rangez vos sabres laser!) et son contenu.

android:paddingBotton, android:paddingTop, android:paddingLeft et android:paddingRight s’utilisent indépendamment selon les besoins.

Les valeurs utilisent les mêmes unités que les marges, la hauteur et la largeur.

L’ID

Tous les widgets peuvent avoir un ID, on retrouve donc naturellement cette propriété dans la liste des propriétés communes à tous les widgets. Tout comme sous Xaml avec “x:Name”, l’ID n’est pas obligatoire mais il est indispensable si le code veut accéder au contrôle. Avec le binding ajouté par MvvmCross les ID ne sont généralement pas utilisés, tout comme les “x:Name” en Xaml. Mais dans le mode de programmation natif il faut savoir qu’à la différence de Xaml la déclaration de l’ID dans le code XML ne créée par automatiquement une variable de même nom pointant le widget dans le “code-behind” de l’activité Android. Il faut alors utiliser une technique qui consiste lors de l’initialisation de l’activité à faire un FindViewByID pour récupérer un pointeur sur le widget. On se sert parfois de ce genre de chose en ASP.Net par exemple et sous Xaml c’est le compilateur qui s’occupe de créer automatiquement ces déclarations. Le principe est donc le même que son Xaml mais en moins automatisé.

La déclaration d’un ID dépend de si on référence un ID existant ou bien si on souhaite déclarer l’ID lors de sa première apparition.

Pour déclarer un ID on utiliser l’attribut android:id=”@+id/btnCancel” par exemple pour un bouton qui portera le nom de “btnCancel”. Cette notation indique au compilateur de créer l’ID et de la placer dans le fichier des ressources afin d’y créer un véritable ID. En effet, Android ne gère que des ID numériques en réalité. Pour éviter d’avoir à travailler avec de tels identifiants peu pratique, le fichier R.java (qu’on retrouve sous Xamarin d’une façon similaire) contient la liste des ID “humains” déclarés dans le fichier Xml ainsi qu’une véritable valeur numérique associée. Cela permet dans le code de référencer un widget par son nom “humain” tout en accédant à son véritable ID numérique. Dans R.java (ou équivalent Xamarin) l’ID est donc déclaré comme une simple constante integer dont la valeur est choisie par le compilateur.

Pour référencer un widget sans déclarer son ID on utilise la syntaxe suivante : “@id/btnCancel” (si on suppose une référence au bouton btnCancel). Cette syntaxe ne s’utilise qu’à l’intérieur d’un fichier Xml puisque dans le code Java ou C# on peut directement accéder à l’objet par son ID “humain”.

L’intérêt de référencer un widget dans un fichier Xml s’explique notamment par la présence de certains modes de mise en page qui utilisent des positionnements relatifs (RelativeLayout). Dans ce cas les contrôles sont placés au-dessus, en-dessous, à gauche ou à droite relativement à un autre contrôle dont il faut donner l’ID.

Couleurs

Les couleurs sont aussi des attributs de base. On trouve le android:background qui peut être pour tout contrôle aussi bien une couleur qu’une référence à une image placée en ressources.

La couleur du texte, si le contrôle en affiche, se modifie avec android:textColor. C’est le cas des boutons ou des TextView (équivalent au TextBlock Xaml) par exemple.

Les couleurs s’expriment indifféremment avec les formats suivants :

“#rrggbb”, “#aarrggbb”, “@color/colorName”

Les valeurs sont en hexadécimal. Dans le premier cas on définit une couleur pleine, dans le second cas on définit une couleur ainsi que son canal alpha pour la transparence, comme en Xaml. Dans le dernier cas on pointe vers le nom d’une couleur définie dans l’arborescence du projet au sein d’un fichier Xml.

Gestion du clic

Le clic est aussi partie intégrante des propriétés de base, tout objet peut donc recevoir et gérer un appui du doigt. Le gestionnaire se définit par android:onClick avec le nom d’une méthode publique dans l’activité qui prend une View comme argument et qui retourne void. Toutefois avec MvvmCross on utilise plutôt un MvxBind pour se lier à un ICommand dans le ViewModel.

Le conteneur linéaire LinearLayout

Ce conteneur est très utilisé comme son équivalent Xaml le StackPanel. Il fonctionne de la même façon, peut être horizontal ou vertical et sert à empiler des contrôles les uns derrière les autres ou les uns haut de dessus de l’autre.

En le combinant avec lui-même, tout comme en Xaml, on peut construire des mises en page dynamiques très efficacement. Un LinearLayout vertical contenant des LinearLayout horizontaux forme une sorte de tableau totalement ajustable par exemple.

Son attribut principal est android:orientation qui prend les valeurs horizontal ou vertical. Le mode horizontal est la valeur par défaut (inutile de déclarer l’attribut dans ce cas).

L’attribut android:gravity est aussi très souvent utilisé dans un LinearLayout car il permet de définir comment les widgets contenus sont alignés. Les valeurs acceptées sont nombreuses : top, bottom, left, right, center_vertical, center_horizontal, center, fill_vertical, fill_horizontal, fill, clip_vertical, clip_horizontal.

La déclaration d’un conteneur linéaire ressemble à cela :

image

Voici un exemple de mise en page utilisant ce conteneur :

image

Cette mise en page s’explique par les placements suivants (les couleurs de fond sont là pour délimiter les zones des différents LinearLayout utilisés pour vous faciliter la lecture et n’ont aucune vocation d’exemple visuel – c’est réellement atroce ne faite jamais une UI comme celle-là et si vous le faites ne dites surtout pas que vous connaissez Dot.Blog, le département d’Etat niera avoir eu connaissance de vos agissements – et je placerai personnellement un contrat sur votre tête Sourire !!!) :

image

image

image

image

image

Définir les couleurs

Comme nous l’avons vu, les couleurs se définissent le plus simplement du monde par un code hexadécimal sur 6 ou huit chiffres selon qu’on intègre ou non le canal alpha.

Bien entendu cette façon de faire ne peut se comprendre que dans une démo… Toute application bien faite et donc bien designée se doit d’utiliser des feuilles de style facilement modifiable et centralisées pour assurer l’homogénéité visuelle indissociable d’une bonne UI. Chaque plateforme propose sa façon de créer des feuilles de style. Sous Xaml on utilise des templates de contrôle et des dictionnaires. Sous Android les choses marchent de façon différentes mais l’esprit reste similaire.

Tout comme on peut définir des couleurs dans un dictionnaire de ressources Xaml on peut le faire dans un fichier Xml sous Android, fichier qui sera placé dans l’arborescence des ressources du projet.

La syntaxe d’un tel fichier est fort simple :

<resources>
<color name=”maCouleur”>#rrggbb</color>

</resources>

Par convention les définitions de couleurs dans un projet Xaml se place dans un fichier appelé colors.xml lui-même placé dans l’arborescence res/values/

Les fichiers Xml de définitions des écrans peuvent référencer les ressources couleur par leur nom.

Si on définit un fichier de couleur res/values/colors.xml de la façon suivante :

image

On peut alors utiliser les définitions créées de cette façon dans un autre fichier Xml :

image

Localisation et fichiers de valeurs

Les couleurs comme tout fichier de valeurs se trouvant dans le répertoire res/values peuvent être définies selon la valeur de la locale (le code langue) de l’utilisateur.

Il suffit pour cela de créer une copie du fichier placé dans res/values et de le placer dans un sous-répertoire de même niveau que values mais incluant le code de la locale, par exemple res/values-fr.

Le fichier se trouvant dans le nouveau répertoire peut ainsi être modifié et Android le chargement automatiquement en place et lieu de celui situé dans values (si la locale correspond, sinon c’est le fichier dans values qui est chargé par défaut).

On peut ainsi définir des fichiers strings.xml pour les chaînes de caractères, des fichiers de couleurs, des données localisées, etc.

Ce système fonctionnant sur des noms de répertoire est un peu “frustre” mais redoublement simple et efficace. On voit ici la différence d’approche entre un OS au départ ultra optimisé pour des petites machines peu puissantes (choisir un répertoire ou un autre est très rapide pour l’OS) et un OS plus sophistiqué comme Windows Phone mais qui réclame parfois des trésors de génie logiciel pour arriver à créer des localisations… L’approche d’Android est toutefois dangereuse et réclame une organisation sans faille des équipes… car comme tout se joue dans le nom des répertoires mais que les fichiers eux-mêmes portent exactement le même nom mais avec un contenu très différent toute erreur de manipulation, de copie ou autre peut être fatale et faire perdre un fichier bêtement écrasé par un autre… Une gestion de version est fortement conseillée !

Deux poids deux mesures !

Gérer des tableaux ou des objets dont les dimensions sont des pourcentages plutôt que des valeurs numériques précises est un besoin vieux comme Html couvert de diverses façons par des systèmes comme Xaml ou Android.

Sous Xaml la définition des Rows et Columns dans une Grid autorise, via une syntaxe parfois obscure pour le débutant, de définir les hauteurs et les largeurs par des pourcentages. Android propose la même chose mais en utilisant une déclaration séparée, clarifiant un peu les choses.

L’idée est donc de pouvoir assigner des nombres à l’attribut android:weight, le rendu étant proportionnel à la somme de ces nombres quels qu’ils soient. En général, à moins d’être maso, on se débrouille pour que la somme de ces nombres soit égale à 10 ou à 100 (le plus souvent) mais les valeurs farfelues sont aussi acceptées (comme sous Xaml) bien que déconseillées…

Ainsi, si trois objets ont une largeur respective (un poids) de 10, 40 et 50, la somme valant 100, les trois objets occuperont respectivement 10%, 40% et 50% de la largeur disponible du conteneur. Mais on peut obtenir le même résultat avec les trois poids suivants : 1, 4 et 5, ou bien 4.8 19.2 et 24 ( somme = 48, 4.8 = 10% de 48, 19.2 = 40% de 48 etc).

Le procédé est en deux étapes : la première consiste à mettre la hauteur ou la largeur à zéro et ensuite d’assigner une valeur au poids (weight). Le poids est global, si seule la hauteur est mise à zéro, seule la hauteur sera proportionnelle, idem pour la largeur, mais si les deux valeurs sont à zéro l’effet du poids se fera sentir sur les deux paramètres.

Voici un exemple de code utilisant ce type de mise en page :

image

Tout est relatif !

Android propose de nombreux modes de mise en page, de conteneurs utilisant des règles différentes, tout comme Xaml. Le conteneur que nous allons maintenant voir est un peu spécial et n’a pas d’équivalent sous Xaml, c’est le conteur relatif ou RelativeLayout.

Bien entendu tous les conteneurs pouvant s’imbriquer, on peut construire des affichages très complexes mixant les effets et bénéfices de tous les modes disponibles. Savoir rester simple et ne pas hésiter à refaire un Design qui devient trop compliqué est aussi important que savoir refactorer un code C# qui devient confus.

L’idée derrière le conteneur relatif est qu’une fois qu’on a attribué un identifiant à au moins un widget il devient possible de placer les autres par rapport à ce dernier (au-dessus ou en-dessous par exemple). On a bien entendu le droit d’attribuer un identifiant à plusieurs widgets et de faire des placements relatifs les uns par rapports aux autres. Attention, comme je le disais, ce mode de construction peut devenir rapidement impossible à maintenir, une sorte de code spaghetti au niveau de l’UI…

Les attributs les plus importants dans une mise en page relatives sont ceux qui concernent l’alignement avec le conteneur et l’alignement avec d’autres contrôles situés dans le même conteneur.

android:layout_alignParentBottom (et en variante Top, Left, Right) ainsi que android:layout_CenterInParent (et CenterHorizontal, CenterVertical) concernent l’alignement par rapport au conteneur. Ces attributs sont des booléens prenant la valeur true ou false.

android:layout_alignBottom (et Top, Left, Right) ainsi que android:layout_toLeftOf (et toRightOf) ou android:layout_above (et below) concernent l’alignement d’un contrôle par rapport à une autre dans le conteneur. Ces attributs prennent tous une valeur qui est l’ID du contrôle de référence (par exemple android:layout_alignTop=”@id/id_du_widget”)

Un placement simple de deux boutons dont l’un est la référence positionnelle donnerait cela (décomposé) :

image

La déclaration du premier bouton utilise un “@+id” pour créer l’ID “button_1”. Ce bouton est aligné à droite dans son parent.

La déclaration du second bouton utilise un placement relatif au premier, la référence à l’ID ne contient pas de symbole “+” puisqu’il ne s’agit pas de créer un ID mais d’en référencer un qui existe. Le placement est de type “à la gauche de”.

Le résultat visuel est montré par les deux boutons oranges, le bouton 1 est à droite et le 2 est à la gauche du 1er.

A table !

On dira ce qu’on voudra mais bien souvent une bonne vieille table Html c’est bien pratique ! Surtout si elle a été un peu modernisée. C’est finalement ce qu’est une Grid Xaml avec ses définitions de lignes et colonnes.

Android nous propose un conteneur ayant le même but : le TableLayout.

L’idée est simple, placer les widgets or des conteneurs imbriqués dans une grille. Sans bordure. Comme dans Html le nombre des colonnes et des lignes est déduit automatiquement en fonction du contenu. C’est plus souple que la Grid Xaml de ce point de vue. Les contrôles sont placés généralement dans des TableRow.

Les attributs les plus importants de ce conteneur ;

android:stretchColumns. Sa valeur est constituée d’un index ou d’une liste d’index séparés par des virgules. Cet index ou cette liste d’index spécifie la colonne ou les colonnes qui doivent être stretchées au plus large si la table est rétrécie en deçà de celle de son parent. Les index sont 0-based.

android:shrinkColumns. Dans le même principe mais cette fois pour lister les colonnes qui doivent être rétrécies si la table est plus grande que le parent.

android:collapseColumns. Définit les colonnes qui disparaissent totalement. En général cette liste est manipulée codée code en fonction des choix de l’utilisateur plutôt que figée au design (une colonne invisible posée au design “en dur” est une colonne qui ne sera jamais visible, alors autant ne pas la coder…).

La TableRow

Elle sert à définir une ligne dans un TableLayout. Techniquement des éléments peuvent exister entre les TableRow mais le résultat est bien plus propre en utilisant android:layout_span.

Les attributs essentiels de la Row :

android:layout_column. Normalement une table se remplit de la gauche vers la droite en fonction de l’ordre des éléments placés dans les colonnes. En spécifiant une valeur à cet attribut on peut placer un élément dans n’importe quelle colonne.

android:layout_span. Indique le nombre de colonnes à regrouper de la même façon qu’un colspan en Html.

On notera qu’il n’y a pas d’équivalent au rowspan Html, il faut donc utiliser des tables imbriquées pour obtenir le même résultat.

L’Approche générale est résumée ici :

image

image

image

image

Les autres conteneurs

Même si les conteneurs que nous venons de voir sont les plus utilisés et suffisent à la majorité des applications, Android en propose d’autres qu’il faut connaître.

Le premier est l’équivalent du Canvas Xaml, c’est le AbsoluteLayout qui utilise, comme son nom l’indique, des positions absolues. Totalement inadapté au foisonnement des résolutions et des densités, ce conteneur est aujourd’hui deprecated.

Le FrameLayout est un conteneur qui ne prend qu’un seul enfant. Il est généralement utilisé avec le TabHost. Sinon il est utilisé en interne par d’autres conteneurs.

Le TabHost est le plus intéressant des conteneurs non vus ici. c’est un contrôle avec des tabulations qui permet de passer d’une activité à une autre. Il mérite plus d’explications qui n’auraient pu tenir ici ce n’est donc pas le manque d’intérêt qui le pousse en fin d’article !

C’est le cas aussi du ListView et du GridView. Toutefois concernant le ListView, une sorte de ListBox Xaml, on préfèrera la MvxListView fournie par MvvmCross qui possède des propriétés bindables plus adaptées à notre stratégie de développement. La MvxListView a été traitée de nombreuses fois dans la série récente de vidéos (voir en introduction de cet article).

Conclusion

Cet article avait pour principal objectif de vous donner un aperçu rapide et condensé des bases de la mise en page sous Android. Il reste des milliers de choses à dire, à présenter chaque widget, ses propriétés, etc… C’est l’œuvre d’un livre plus que d’un billet de blog !

J’ai certes habitué mes lecteurs aux billets à rallonge et aux papiers dépassant les 100 pages, donc à des livres qui ne disent pas leur nom… Mais il faut bien en laisser un peu pour les prochains billets !

Donc … Stay Tuned !

blog comments powered by Disqus