Organiser son interface avec des layouts

Ce contenu est obsolète. Il peut contenir des informations intéressantes mais soyez prudent avec celles-ci.

Pour l'instant, la racine de tous nos layouts a toujours été la même, ce qui fait que toutes nos applications avaient exactement le même squelette ! Mais il vous suffit de regarder n'importe quelle application Android pour réaliser que toutes les vues ne sont pas forcément organisées comme cela et qu'il existe une très grande variété d'architectures différentes. C'est pourquoi nous allons maintenant étudier les différents layouts, afin d'apprendre à placer nos vues comme nous le désirons. Nous pourrons ainsi concevoir une application plus attractive, plus esthétique et plus ergonomique ! :D

LinearLayout : placer les éléments sur une ligne

Comme son nom l'indique, ce layout se charge de mettre les vues sur une même ligne, selon une certaine orientation. L'attribut pour préciser cette orientation est android:orientation. On peut lui donner deux valeurs :

  • vertical pour que les composants soient placés de haut en bas (en colonne) ;
  • horizontal pour que les composants soient placés de gauche à droite (en ligne).

On va faire quelques expériences pour s'amuser !

Premier exemple

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent" >
  <Button  
    android:id="@+id/premier"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="Premier bouton" />

  <Button  
    android:id="@+id/second"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="Second bouton" />
</LinearLayout>

Le rendu de ce code se trouve à la figure suivante.

Les deux boutons prennent toute la largeur

  • Le LinearLayout est vertical et prend toute la place de son parent (vous savez, l'invisible qui prend toute la place dans l'écran).
  • Le premier bouton prend toute la place dans le parent en largeur et uniquement la taille nécessaire en hauteur (la taille du texte, donc !).
  • Le second bouton fait de même.

Deuxième exemple

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent" >

  <Button  
    android:id="@+id/premier"
    android:layout_width="wrap_content" 
    android:layout_height="fill_parent" 
    android:text="Premier bouton" />

  <Button  
    android:id="@+id/second"
    android:layout_width="wrap_content" 
    android:layout_height="fill_parent" 
    android:text="Second bouton" />
</LinearLayout>

Le rendu de ce code se trouve à la figure suivante.

Le premier bouton fait toute la hauteur, on ne voit donc pas le deuxième bouton

  • Le LinearLayout est vertical et prend toute la place de son parent.
  • Le premier bouton prend toute la place de son parent en hauteur et uniquement la taille nécessaire en largeur.
  • Comme le premier bouton prend toute la place, alors le pauvre second bouton se fait écraser. :( C'est pour cela qu'on ne le voit pas.

Troisième exemple

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content" >
  <Button  
    android:id="@+id/premier"
    android:layout_width="wrap_content"
    android:layout_height="fill_parent" 
    android:text="Premier bouton" />
  <Button  
    android:id="@+id/second"
    android:layout_width="wrap_content" 
    android:layout_height="fill_parent" 
    android:text="Second bouton" />
</LinearLayout>

Le rendu de ce code se trouve à la figure suivante.

Les deux boutons prennent uniquement la place nécessaire en hauteur et en largeur

  • Le LinearLayout est vertical et prend toute la place en largeur mais uniquement la taille nécessaire en hauteur : dans ce cas précis, la taille nécessaire sera calculée en fonction de la taille des enfants.
  • Le premier bouton prend toute la place possible dans le parent. Comme le parent prend le moins de place possible, il doit faire de même.
  • Le second bouton fait de même.

Quatrième exemple

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="horizontal"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent" >
  <Button  
    android:id="@+id/premier"
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:text="Premier bouton" />
  <Button  
    android:id="@+id/second"
    android:layout_width="wrap_content" 
    android:layout_height="fill_parent" 
    android:text="Second bouton" />
</LinearLayout>

Le rendu de ce code se trouve à la figure suivante.

Le premier bouton prend uniquement la place nécessaire et le deuxième toute la hauteur

  • Le LinearLayout est horizontal et prend toute la place de son parent.
  • Le premier bouton prend uniquement la place nécessaire.
  • Le second bouton prend uniquement la place nécessaire en longueur et s'étend jusqu'aux bords du parent en hauteur.

Vous remarquerez que l'espace est toujours divisé entre les deux boutons, soit de manière égale, soit un bouton écrase complètement l'autre. Et si on voulait que le bouton de droite prenne deux fois plus de place que celui de gauche par exemple ?

Pour cela, il faut attribuer un poids au composant. Ce poids peut être défini grâce à l'attribut android:layout_weight. Pour faire en sorte que le bouton de droite prenne deux fois plus de place, on peut lui mettre android:layout_weight="1" et mettre au bouton de gauche android:layout_weight="2". C'est alors le composant qui a la plus faible pondération qui a la priorité.

Et si, dans l'exemple précédent où un bouton en écrasait un autre, les deux boutons avaient eu un poids identique, par exemple android:layout_weight="1" pour les deux, ils auraient eu la même priorité et auraient pris la même place. Par défaut, ce poids est à 0.

Une astuce que j'utilise souvent consiste à faire en sorte que la somme des poids dans un même layout fasse 100. C'est une manière plus évidente pour répartir les poids.

Dernier attribut particulier pour les widgets de ce layout, android:layout_gravity, qu'il ne faut pas confondre avec android:gravity. android:layout_gravity vous permet de déterminer comment se placera la vue dans le parent, alors que android:gravity vous permet de déterminer comment se placera le contenu de la vue à l'intérieur même de la vue (par exemple, comment se placera le texte dans un TextView ? Au centre, en haut, à gauche ?).

Vous prendrez bien un petit exemple pour illustrer ces trois concepts ? :)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="horizontal"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent" >
  <Button
    android:id="@+id/bouton1"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:layout_gravity="bottom"
    android:layout_weight="40"
    android:text="Bouton 1" />
  <Button
    android:id="@+id/bouton2"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:layout_gravity="center"
    android:layout_weight="20"
    android:gravity="bottom|right"
    android:text="Bouton 2" />
  <Button
    android:id="@+id/bouton3"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:layout_gravity="top"
    android:layout_weight="40"
    android:text="Bouton 3" />
</LinearLayout>

Le rendu de ce code se trouve à la figure suivante.

Trois boutons placés différemment

Comme le bouton 2 a un poids deux fois inférieur aux boutons 1 et 3, alors il prend deux fois plus de place qu'eux. De plus, chaque bouton possède un attribut android:layout_gravity afin de que l'on détermine sa position dans le layout. Le deuxième bouton présente aussi l'attribut android:gravity, qui est un attribut de TextView et non layout, de façon à mettre le texte en bas (bottom) à droite (right).

Calcul de l'IMC - Partie 3.1

Énoncé

Récupérez le code de votre application de calcul de l'IMC et modifiez le layout pour obtenir quelque chose ressemblant à la figure suivante.

Essayez d'obtenir la même interface

Les EditText prennent le plus de place possible, mais comme ils ont un poids plus fort que les TextView, ils n'ont pas la priorité.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent" 
  android:orientation="vertical">
  <LinearLayout 
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
  >
    <TextView 
      android:layout_width="wrap_content"
      android:layout_height="wrap_content" 
      android:text="Poids : "
      android:textStyle="bold"
      android:textColor="#FF0000"
      android:gravity="center"
    />
    <EditText 
      android:id="@+id/poids"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content" 
      android:hint="Poids"
      android:inputType="numberDecimal"
      android:layout_weight="1"
    />
  </LinearLayout>
  <LinearLayout 
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
  >
    <TextView 
      android:layout_width="wrap_content"
      android:layout_height="wrap_content" 
      android:text="Taille : "
      android:textStyle="bold"
      android:textColor="#FF0000"
      android:gravity="center"
    />
    <EditText 
      android:id="@+id/taille"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content" 
      android:hint="Taille"
      android:inputType="numberDecimal"
      android:layout_weight="1"
    />
  </LinearLayout>
  <RadioGroup
    android:id="@+id/group"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:checkedButton="@+id/radio2"
    android:orientation="horizontal"
  >
    <RadioButton 
      android:id="@+id/radio1"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Mètre"
    />
    <RadioButton 
      android:id="@+id/radio2"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Centimètre"
    />
  </RadioGroup>
  <CheckBox 
    android:id="@+id/mega"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Mega fonction !"
  />
  <LinearLayout 
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
  >
    <Button 
      android:id="@+id/calcul"
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:text="Calculer l'IMC"
      android:layout_weight="1"
      android:layout_marginLeft="25dip" 
      android:layout_marginRight="25dip"
    />
    <Button 
      android:id="@+id/raz"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="RAZ"
      android:layout_weight="1" 
      android:layout_marginLeft="25dip" 
      android:layout_marginRight="25dip"
    />
  </LinearLayout>
  <TextView 
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" 
    android:text="Résultat:"
  />
  <TextView 
    android:id="@+id/result"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" 
    android:text="Vous devez cliquer sur le bouton « Calculer l'IMC » pour obtenir un résultat."
  />
</LinearLayout>

De manière générale, on évite d'empiler les LinearLayout (avoir un LinearLayout dans un LinearLayout, dans un LinearLayout, etc.), c'est mauvais pour les performances d'une application.

RelativeLayout : placer les éléments les uns en fonction des autres

De manière totalement différente, ce layout propose plutôt de placer les composants les uns par rapport aux autres. Il est même possible de les placer par rapport au RelativeLayout parent.

Si on veut par exemple placer une vue au centre d'un RelativeLayout, on peut passer à cette vue l'attribut android:layout_centerInParent="true". Il est aussi possible d'utiliser android:layout_centerHorizontal="true" pour centrer, mais uniquement sur l'axe horizontal, de même avec android:layout_centerVertical="true" pour centrer sur l'axe vertical.

Premier exemple

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent" >

  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Centré dans le parent"
    android:layout_centerInParent="true" />
  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Centré verticalement"
    android:layout_centerVertical="true" />
  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Centré horizontalement"
    android:layout_centerHorizontal="true" />

</RelativeLayout>

Le rendu de ce code se trouve à la figure suivante.

Deux vues sont empilées

On observe ici une différence majeure avec le LinearLayout : il est possible d'empiler les vues. Ainsi, le TextView centré verticalement s’entremêle avec celui centré verticalement et horizontalement.

Il existe d'autres contrôles pour situer une vue par rapport à un RelativeLayout. On peut utiliser :

  • android:layout_alignParentBottom="true" pour aligner le plancher d'une vue au plancher du RelativeLayout ;
  • android:layout_alignParentTop="true" pour coller le plafond d'une vue au plafond du RelativeLayout ;
  • android:layout_alignParentLeft="true" pour coller le bord gauche d'une vue avec le bord gauche du RelativeLayout ;
  • android:layout_alignParentRight="true" pour coller le bord droit d'une vue avec le bord droit du RelativeLayout.

Deuxième exemple

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent" >
  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="En haut !"
    android:layout_alignParentTop="true" />
  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="En bas !"
    android:layout_alignParentBottom="true" />    
  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="A gauche !"
    android:layout_alignParentLeft="true" />
  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="A droite !"
    android:layout_alignParentRight="true" />
  <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Ces soirées là !"
    android:layout_centerInParent="true" />
</RelativeLayout>

Le rendu de ce code se trouve à la figure suivante.

En haut à gauche, deux TextView se superposent

On remarque tout de suite que les TextView censés se situer à gauche et en haut s'entremêlent, mais c'est logique puisque par défaut une vue se place en haut à gauche dans un RelativeLayout. Donc, quand on lui dit « Place-toi à gauche » ou « Place-toi en haut », c'est comme si on ne lui donnait pas d'instructions au final.

Enfin, il ne faut pas oublier que le principal intérêt de ce layout est de pouvoir placer les éléments les uns par rapport aux autres. Pour cela il existe deux catégories d'attributs :

  • Ceux qui permettent de positionner deux bords opposés de deux vues différentes ensemble. On y trouve android:layout_below (pour aligner le plafond d'une vue sous le plancher d'une autre), android:layout_above (pour aligner le plancher d'une vue sur le plafond d'une autre), android:layout_toRightOf (pour aligner le bord gauche d'une vue au bord droit d'une autre) et android:layout_toLeftOf (pour aligner le bord droit d'une vue au bord gauche d'une autre).
  • Ceux qui permettent de coller deux bords similaires ensemble. On trouve android:layout_alignBottom (pour aligner le plancher de la vue avec le plancher d'une autre), android:layout_alignTop (pour aligner le plafond de la vue avec le plafond d'une autre), android:layout_alignLeft (pour aligner le bord gauche d'une vue avec le bord gauche d'une autre) et android:layout_alignRight (pour aligner le bord droit de la vue avec le bord droit d'une autre).

Troisième exemple

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent" >
  <TextView
    android:id="@+id/premier"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="[I] En haut à gauche par défaut" />
  <TextView
    android:id="@+id/deuxieme"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="[II] En dessous de (I)"
    android:layout_below="@id/premier" />    
  <TextView
    android:id="@+id/troisieme"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="[III] En dessous et à droite de (I)"
    android:layout_below="@id/premier"
    android:layout_toRightOf="@id/premier" />
  <TextView
    android:id="@+id/quatrieme"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="[IV] Au dessus de (V), bord gauche aligné avec le bord gauche de (II)"
    android:layout_above="@+id/cinquieme"
    android:layout_alignLeft ="@id/deuxieme" />
  <TextView
    android:id="@+id/cinquieme"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="[V] En bas à gauche"
    android:layout_alignParentBottom="true"
    android:layout_alignParentRight="true" />
</RelativeLayout>

Le rendu de ce code se trouve à la figure suivante.

Les TextView sont bien placés

Je vous demande maintenant de regarder l'avant dernier TextView, en particulier son attribut android:layout_above. On ne fait pas référence au dernier TextView comme aux autres, il faut préciser un + ! Eh oui, rappelez-vous, je vous avais dit il y a quelques chapitres déjà que, si nous voulions faire référence à une vue qui n'était définie que plus tard dans le fichier XML, alors il fallait ajouter un + dans l'identifiant, sinon Android pensera qu'il s'agit d'une faute et non d'un identifiant qui sera déclaré après.

Calcul de l'IMC - Partie 3.2

Même chose pour un layout différent ! Moi, je vise le même résultat que précédemment.

Ma solution

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">
  <TextView 
    android:id="@+id/textPoids"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" 
    android:text="Poids : "
    android:textStyle="bold"
    android:textColor="#FF0000"
  />
  <EditText 
    android:id="@+id/poids"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" 
    android:hint="Poids"
    android:inputType="numberDecimal"
    android:layout_toRightOf="@id/textPoids"
    android:layout_alignParentRight="true"
  />
  <TextView 
    android:id="@+id/textTaille"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" 
    android:text="Taille : "
    android:textStyle="bold"
    android:textColor="#FF0000"
    android:gravity="left"
    android:layout_below="@id/poids"
  />
  <EditText 
    android:id="@+id/taille"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" 
    android:hint="Taille"
    android:inputType="numberDecimal"
    android:layout_below="@id/poids"
    android:layout_toRightOf="@id/textTaille"
    android:layout_alignParentRight="true"
  />
  <RadioGroup
    android:id="@+id/group"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:checkedButton="@+id/radio2"
    android:orientation="horizontal"
    android:layout_below="@id/taille"
  >
    <RadioButton 
      android:id="@+id/radio1"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Mètre"
    />
    <RadioButton 
      android:id="@+id/radio2"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Centimètre"
    />
  </RadioGroup>
  <CheckBox 
    android:id="@+id/mega"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Mega fonction !"
    android:layout_below="@id/group"
  />
  <Button 
    android:id="@+id/calcul"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Calculer l'IMC"
    android:layout_below="@id/mega"
    android:layout_marginLeft="25dip"
  />
  <Button 
    android:id="@+id/raz"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="RAZ"
    android:layout_below="@id/mega"
    android:layout_alignRight="@id/taille"
    android:layout_marginRight="25dip"
  />
  <TextView 
    android:id="@+id/resultPre"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" 
    android:text="Résultat:"
    android:layout_below="@id/calcul"
  />
  <TextView 
    android:id="@+id/result"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" 
    android:text="Vous devez cliquer sur le bouton « Calculer l'IMC » pour obtenir un résultat."
    android:layout_below="@id/resultPre"
  />
</RelativeLayout>

Le problème de ce layout, c'est qu'une petite modification dans l'interface graphique peut provoquer de grosses modifications dans tout le fichier XML, il faut donc savoir par avance très précisément ce qu'on veut faire.

Il s'agit du layout le plus compliqué à maîtriser, et pourtant le plus puissant tout en étant l'un des moins gourmands en ressources. Je vous encourage fortement à vous entraîner à l'utiliser.

TableLayout : placer les éléments comme dans un tableau

Dernier layout de base, il permet d'organiser les éléments en tableau, comme en HTML, mais sans les bordures. Voici un exemple d'utilisation de ce layout :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:stretchColumns="1">
  <TextView 
    android:text="Les items précédés d'un V ouvrent un sous-menu"
  />
  <View
    android:layout_height="2dip"
    android:background="#FF909090"
  />
  <TableRow>
    <TextView 
      android:text="N'ouvre pas un sous-menu"
      android:layout_column="1"
      android:padding="3dip" 
    />
    <TextView 
      android:text="Non !"
      android:gravity="right"
      android:padding="3dip" 
    />
  </TableRow>
  <TableRow>
    <TextView 
      android:text="V"
    />
    <TextView 
      android:text="Ouvre un sous-menu"
      android:layout_column="1"
      android:padding="3dip" 
    />
    <TextView 
      android:text="Là si !"
      android:gravity="right"
      android:padding="3dip" 
    />
  </TableRow>
  <View
    android:layout_height="2dip"
    android:background="#FF909090" 
  />
  <TableRow>
    <TextView 
      android:text="V" 
    />
    <TextView 
      android:text="Ouvre un sous-menu"
      android:padding="3dip"
    />
  </TableRow>
  <View
    android:layout_height="2dip"
    android:background="#FF909090" 
  />
  <TableRow>
    <TextView 
      android:layout_column="1"
      android:layout_span="2"
      android:text="Cet item s'étend sur deux colonnes, cool hein ?"
      android:padding="3dip" 
    />
  </TableRow>
</TableLayout>

Ce qui donne la figure suivante.

Le contenu est organisé en tableau

On observe tout d'abord qu'il est possible de mettre des vues directement dans le tableau, auquel cas elles prendront toute la place possible en longueur. En fait, elles s'étendront sur toutes les colonnes du tableau. Cependant, si on veut un contrôle plus complet ou avoir plusieurs éléments sur une même ligne, alors il faut passer par un objet <TableRow>.

1
2
<TextView 
  android:text="Les items précédés d'un V ouvrent un sous-menu" />

Cet élément s'étend sur toute la ligne puisqu'il ne se trouve pas dans un <TableRow>

1
2
3
<View
  android:layout_height="2dip"
  android:background="#FF909090" />

Moyen efficace pour dessiner un séparateur — n'essayez pas de le faire en dehors d'un <TableLayout> ou votre application plantera.

Une ligne est composée de cellules. Chaque cellule peut contenir une vue, ou être vide. La taille du tableau en colonnes est celle de la ligne qui contient le plus de cellules. Dans notre exemple, nous avons trois colonnes pour tout le tableau, puisque la ligne avec le plus cellules est celle qui contient « V » et se termine par « Là si ! ».

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<TableRow>
  <TextView 
    android:text="V" 
  />
  <TextView 
    android:text="Ouvre un sous-menu"
    android:layout_column="1"
    android:padding="3dip" 
  />
  <TextView 
    android:text="Là si !"
    android:gravity="right"
    android:padding="3dip" 
  />
</TableRow>

Cette ligne a trois éléments, c'est la plus longue du tableau, ce dernier est donc constitué de trois colonnes.

Il est possible de choisir dans quelle colonne se situe un item avec l'attribut android:layout_column. Attention, l'index des colonnes commence à 0. Dans notre exemple, le dernier item se place directement à la deuxième colonne grâce à android:layout_column="1".

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<TableRow>
  <TextView 
    android:text="N'ouvre pas un sous-menu"
    android:layout_column="1"
    android:padding="3dip" 
  />
  <TextView 
    android:text="Non !"
    android:gravity="right"
    android:padding="3dip" 
  />
</TableRow>

On veut laisser vide l'espace pour la première colonne, on place alors les deux TextView dans les colonnes 1 et 2.

La taille d'une cellule dépend de la cellule la plus large sur une même colonne. Dans notre exemple, la seconde colonne fait la largeur de la cellule qui contient le texte « N'ouvre pas un sous-menu », puisqu'il se trouve dans la deuxième colonne et qu'il n'y a pas d'autres éléments dans cette colonne qui soit plus grand.

Enfin, il est possible d'étendre un item sur plusieurs colonnes à l'aide de l'attribut android:layout_span. Dans notre exemple, le dernier item s'étend de la deuxième colonne à la troisième. Il est possible de faire de même sur les lignes avec l'attribut android:layout_column.

1
2
3
4
5
6
7
8
<TableRow>
  <TextView 
    android:layout_column="1"
    android:layout_span="2"
    android:text="Cet item s'étend sur deux colonnes, cool hein ?"
    android:padding="3dip" 
  />
</TableRow>

Ce TextView débute à la deuxième colonne et s'étend sur deux colonnes, donc jusqu'à la troisième.

Sur le nœud TableLayout, on peut jouer avec trois attributs (attention, les rangs débutent à 0) :

  • android:stretchColumns pour que la longueur de tous les éléments de cette colonne passe en fill_parent, donc pour prendre le plus de place possible. Il faut préciser le rang de la colonne à cibler, ou plusieurs rangs séparés par des virgules.
  • android:shrinkColumns pour que la longueur de tous les éléments de cette colonne passe en wrap_content, donc pour prendre le moins de place possible. Il faut préciser le rang de la colonne à cibler, ou plusieurs rangs séparés par des virgules.
  • android:collapseColumns pour faire purement et simplement disparaître des colonnes du tableau. Il faut préciser le rang de la colonne à cibler, ou plusieurs rangs séparés par des virgules.

Calcul de l'IMC - Partie 3.3

Énoncé

Réitérons l'expérience, essayez encore une fois d'obtenir le même rendu, mais cette fois avec un TableLayout. L'exercice est intéressant puisqu'on n'est pas vraiment en présence d'un tableau, il va donc falloir réfléchir beaucoup et exploiter au maximum vos connaissances pour obtenir un rendu acceptable.

Ma solution

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
<?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:stretchColumns="1">
  <TableRow>
    <TextView 
      android:text="Poids : "
      android:textStyle="bold"
      android:textColor="#FF0000"
      android:gravity="center"
    />
    <EditText 
      android:id="@+id/poids"
      android:hint="Poids"
      android:inputType="numberDecimal"
      android:layout_span="2"
    />
  </TableRow>
  <TableRow>
    <TextView 
      android:layout_width="fill_parent"
      android:layout_height="wrap_content" 
      android:text="Taille : "
      android:textStyle="bold"
      android:textColor="#FF0000"
      android:gravity="center"
    />
    <EditText 
      android:id="@+id/taille"
      android:layout_width="fill_parent"
      android:layout_height="wrap_content" 
      android:hint="Taille"
      android:inputType="numberDecimal"
      android:layout_span="2"
    />
  </TableRow>
  <RadioGroup
    android:id="@+id/group"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:checkedButton="@+id/radio2"
    android:orientation="horizontal">
    <RadioButton 
      android:id="@+id/radio1"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Mètre"
    />
    <RadioButton 
      android:id="@+id/radio2"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Centimètre"
    />
  </RadioGroup>
  <CheckBox 
    android:id="@+id/mega"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Mega fonction !"
  />
  <TableRow>
    <Button 
      android:id="@+id/calcul"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="Calculer l'IMC"
    />
    <Button 
      android:id="@+id/raz"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="RAZ"
      android:layout_column="2"
    />
  </TableRow>
  <TextView 
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" 
    android:text="Résultat:"
  />
  <TextView 
    android:id="@+id/result"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" 
    android:text="Vous devez cliquer sur le bouton « Calculer l'IMC » pour obtenir un résultat."
  />
</TableLayout>

FrameLayout : un layout un peu spécial

Ce layout est plutôt utilisé pour afficher une unique vue. Il peut sembler inutile comme ça, mais ne l'est pas du tout ! Il n'est destiné à afficher qu'un élément, mais il est possible d'en mettre plusieurs dedans puisqu'il s'agit d'un ViewGroup. Si par exemple vous souhaitez faire un album photo, il vous suffit de mettre plusieurs éléments dans le FrameLayout et de ne laisser qu'une seule photo visible, en laissant les autres invisibles grâce à l'attribut android:visibility (cet attribut est disponible pour toutes les vues). Pareil pour un lecteur de PDF, il suffit d'empiler toutes les pages dans le FrameLayout et de n'afficher que la page actuelle, celle du dessus de la pile, à l'utilisateur. Cet attribut peut prendre trois valeurs :

  • visible (View.VISIBLE), la valeur par défaut.
  • invisible (View.INVISIBLE) n'affiche rien, mais est pris en compte pour l'affichage du layout niveau spatial (on lui réserve de la place).
  • gone (View.GONE) n'affiche rien et ne prend pas de place, un peu comme s'il n'était pas là.

L'équivalent Java de cet attribut est public void setVisibility (int) avec comme paramètre une des valeurs entre parenthèses dans la liste ci-dessus. Quand il y a plusieurs éléments dans un FrameLayout, celui-ci les empile les uns au-dessus des autres, le premier élément du XML se trouvant en dernière position et le dernier ajouté tout au-dessus.

ScrollView : faire défiler le contenu d'une vue

Ne vous laissez pas bernez par son nom, cette vue est bel et bien un layout. Elle est par ailleurs un peu particulière puisqu'elle fait juste en sorte d'ajouter une barre de défilement verticale à un autre layout. En effet, si le contenu de votre layout dépasse la taille de l'écran, une partie du contenu sera invisible à l'utilisateur. De façon à rendre ce contenu visible, on peut préciser que la vue est englobée dans une ScrollView, et une barre de défilement s'ajoutera automatiquement.

Ce layout hérite de FrameLayout, par conséquent il vaut mieux envisager de ne mettre qu'une seule vue dedans. Il s'utilise en général avec LinearLayout, mais peut être utilisé avec tous les layouts… ou bien des widgets ! Par exemple :

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
  <LinearLayout>
    <!-- contenu du layout -->
  </LinearLayout>
</ScrollView>

Attention cependant, il ne faut pas mettre de widgets qui peuvent déjà défiler dans une ScrollView, sinon il y aura conflit entre les deux contrôleurs et le résultat sera médiocre. Nous n'avons pas encore vu de widgets de ce type, mais cela ne saurait tarder.


  • LinearLayout permet d'afficher plusieurs vues sur une même ligne de manière horizontale ou verticale. Il est possible d'attribuer un poids aux vues pour effectuer des placements précis.
  • RelativeLayout permet d'afficher des vues les unes en fonction des autres.
  • TableLayout permet d'organiser les éléments en tableau.
  • FrameLayout permet d'afficher une vue à l'écran ou d'en superposer plusieurs les unes au-dessus des autres.
  • ScrollView permet de rendre « scrollable » la vue qu'elle contient. Attention de ne lui donner qu'un fils et de ne pas fournir des vues déjà « scrollable » sinon il y aura des conflits.