Conception d’interfaces graphiques¶
La plupart des applications Android impliquent une interaction avec l’utilisateur. Nous avons introduit au chapitre précédent la notion d’activité qui correspond à un écran. Dans ce chapitre nous allons voir plus en détail comment créer des activités riches et responsives.
View et Layout¶
Une activité est composée de views. Il s’agit des composants graphiques qui peuvent être affichés à l’écran (on parle plus généralement en programmation de widgets graphiques). Par exemple, une zone de texte ou un bouton sont des views représentés en Java respectivement par les classes TextView et Button. Certaines vues permettent de grouper d’autres vues ensembles (ViewGroup) afin de créer une hiérarchie structurée des composants graphiques à afficher.

Exemple de hiérarchie des composants graphiques d’une activité¶
La difficulté d’une bonne conception d’interfaces graphiques avec Android et de concevoir des activités responsives, c’est-à-dire capables de s’adapter à des configurations diverses : la résolution de l’écran qui varie suivant les modèles d’appareil, la ratio hauteur / largeur de l’écran qui dépend de l’orientation de l’appareil (mode paysage ou mode portrait), la langue utilisée, la configuration de l’utilisateur… De plus une application Android peut parfois être installée sur des appareils très différents : smartphones, tablettes, Smart TV…
Pour aider à la conception d’interfaces graphiques, l’API Android fournit des layouts. Un layout agit comme un ViewGroup : il peut contenir plusieurs vues. Un layout n’a pas de représentation graphique particulière. Cependant, il va positionner à l’écran les vues qu’il contient suivant un modèle et en s’adaptant aux conditions particulières d’affichage. Par exemple, le layout LinearLayoutCompat permet d’organiser toutes le vues qu’il contient horizontalement ou verticalement.
Note
Un layout étant un ViewGroup, cela signifie qu’il peut être placé dans un autre layout. En effet, le rendu d’une activité peut rarement être réalisé grâce à l’utilisation d’un seul layout. Plus généralement, les layouts sont imbriqués les uns dans les autres pour obtenir le rendu voulu.
Layout XML¶
Nous avons vu au chapitre précédent qu’il est possible de créer un fichier XML pour décrire le layout d’une activité (le terme layout est ici à prendre au sens général d’un arrangement de composants graphiques sur l’écran). Au démarrage de l’activité, on associe ce layout grâce à la méthode setContentView :
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
Note
Il est tout à fait possible de réaliser la même opération par programmation en Java. La plupart du temps, le recours à un fichier XML est plus simple et la programmation Java d’un layout est laissée pour des implémentations avancées.
Avec Android Studio, vous avez la possibilité d’utiliser l’outil de conception graphique ou d’éditer et de modifier directement le fichier XML.
Layout linéaire et positionnement¶
Pour illustrer les bases du layout, nous allons utiliser le fichier suivant :
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Bonjour" />
</androidx.appcompat.widget.LinearLayoutCompat>
Ce fichier commence par utiliser un LinearLayoutCompat. Ce dernier permet
d’organiser les vues qu’il contient horizontalement ou verticalement. L’attribut
android:orientation
indique pour cet exemple que le placement sera vertical.

Rendu du layout linéaire vertical¶
Note
On peut également spécifier un orientation horizontale :
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Bonjour" />
</androidx.appcompat.widget.LinearLayoutCompat>

Rendu du layout linéaire horizontal¶
Le layout contient deux TextView avec les libellés : « Hello » et « Bonjour ».
Chacun des éléments dans ce fichier possède les attributs android:layout_width
et android:layout_height
. Ces attributs permettent de définir comment une
vue doit décider de ses dimensions lors de l’affichage à l’écran.
Il est possible de donner les valeurs suivantes :
- match_parent
Le composant doit, autant que possible, adapter sa taille à celle du composant dans lequel il se trouve sans tenir compte de son contenu.
- wrap_content
Le composant doit s’assurer que sa taille d’affichage est suffisante pour afficher correctement son contenu (par exemple le texte pour un TextView).
- fill_parent
Le composant doit simplement recouvrir son composant parent.
Si nous modifions notre fichier layout :
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="Hello"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Bonjour" />
</androidx.appcompat.widget.LinearLayoutCompat>
Nous indiquons maintenant que le premier TextView a une hauteur match_parent
.

Rendu du layout modifié¶
Nous voyons sur le rendu que le second TextView semble avoir disparu. En fait, le premier TextView occupe la totalité de la hauteur du LinearLayoutCompat, qui, lui-même, occupe la totalité de l’activité (c’est-à-dire de l’écran). Le second TextView n’a donc pas disparu, il est placé hors écran, sous le premier.
Note
Vous pouvez également définir une valeur chiffrée pour définir une hauteur ou une largeur d’une vue dans un layout. La valeur peut être exprimée en dp (Density-independent Pixels). Il s’agit d’une unité de mesure basée sur la taille d’un pixel physique pour un écran de 160 dpi (Dots Per Inch). L’avantage de cette mesure est que le système applique un ratio de correction en fonction des capacités réelles de l’écran pour assurer un affichage correct. Même s’il est possible de donner également des mesures en pixels, en centimètres, en millimètres ou en pouce, le dp est la mesure recommandée lorsque vous devez donner une taille chiffrée pour un composant.
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="100dp"
android:text="Hello"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Bonjour" />
</androidx.appcompat.widget.LinearLayoutCompat>

Rendu du layout modifié¶
Techniques avancées de positionnement dans un layout¶
Pour ajuster le rendu d’un layout vous pouvez agir sur chaque vue individuellement avec plusieurs attributs.
layout_margin et padding¶
Vous pouvez définir une marge grâce à l’attribut android:layout_margin
(et
toutes ses variantes : android:layout_marginBottom
, android:layout_marginTop
android:layout_marginHorizontal
, android:layout_marginLeft
,
android:layout_marginRight
, android:layout_marginStart
,
android:layout_marginEnd
, android:layout_marginVertical
) qui permet définir
une marge autour de la vue.
De même, vous pouvez définir un padding grâce à l’attribut android:padding
(et toutes ses variantes : android:paddingBottom
, android:paddingTop
android:paddingHorizontal
, android:paddingLeft
,
android:paddingRight
, android:paddingStart
,
android:paddingEnd
, android:paddingVertical
).
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="50dp"
android:text="Hello"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="50dp"
android:text="Bonjour" />
</androidx.appcompat.widget.LinearLayoutCompat>

Utilisation du layout_margin et du padding¶
Même si, dans les cas les plus simples, il n’y a pas de différence de rendu
entre l’utilisation de android:layout_margin
et de android:padding
, il
faut garder à l’esprit que :
android:layout_margin
définit une marge autour de la vue. Cette marge impacte le comportement du layout qui doit positionner les autres vue en accord.android:padding
définit un écart à l’intérieur de la vue elle-même. Si la vue déclare une largeur et/ou une hauteur à partir dewrap_content
, la vue aura simplement sa largeur et/ou sa hauteur modifiées pour tenir compte du padding. Le padding n’a dont pas d’impact direct sur le layout.
layout_gravity et gravity¶
Les attributs android:layout_gravity
et android:gravity
permettent de
définir comment le contenu d’une vue doit être attiré vers tel ou tel bord
ou au contraire être centré. android:gravity
n’agit que sur le contenu
de la vue indépendamment du reste du layout tandis que android:layout_gravity
agit sur le positionnement de la vue en fonction du layout.
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:text="Hello"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Bonjour" />
</androidx.appcompat.widget.LinearLayoutCompat>

Utilisation du layout_gravity¶
layout_weight¶
Vous pouvez définir un poids pour chaque vue dans un layout grâce à l’attribut
android:layout_weight
. S’il s’agit d’un layout vertical, alors la hauteur
de chaque vue sera proportionnelle à son poids et, respectivement, s’il s’agit
d’un layout horizontal, alors la largeur de chaque vue sera proportionnelle à
son poids. Si la valeur de l’attribut android:layout_weight
est inférieur à
1, alors elle est interprétée comme un pourcentage.
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/holo_orange_dark"
android:layout_weight=".2"
android:text="Hello"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:layout_weight=".3"
android:text="Bonjour" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/holo_purple"
android:layout_weight=".5"
android:text="à tous" />
</androidx.appcompat.widget.LinearLayoutCompat>

Utilisation du layout_weight¶
Dans l’exemple ci-dessus, nous déclarons trois TextView avec des poids respectifs
de 20%, 30% et 50%. Pour que le résultat soit plus facile à comprendre, nous
utilisons également l’attribut android:background
pour attribuer une couleur
prédéfinie comme fond à chaque TextView.
Layout par contraintes¶
Même s’il est possible d’utiliser une combinaison de LinearLayoutCompat pour aligner horizontalement et verticalement les vues, cela finit par créer une arborescence complexe de layouts. Comme alternative, vous pouvez également utiliser un ConstraintLayout. Ce dernier permet de créer plus librement des agencements complexes avec un unique layout au prix, néanmoins, d’une plus grande difficulté de prise en main.
Note
La vue Designer de Android Studio dispose d’outils graphiques pour aider à la conception d’un layout contraint.
Le principe du ConstraintLayout est de positionner les vues les unes par rapport aux autres. Une vue doit au minimum posséder une contrainte pour sa position verticale et une pour sa position horizontale. Par exemple, vous pouvez contraindre un bouton à se positionner à droite d’un autre bouton et à la même hauteur.
Ci-dessous un exemple de layout contraint avec le rendu :
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 | <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView
android:id="@+id/textViewHello"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:layout_marginTop="50dp"
android:text="Hello"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dp"
android:text="world"
app:layout_constraintLeft_toRightOf="@+id/textViewHello"
app:layout_constraintBaseline_toBaselineOf="@+id/textViewHello" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="50dp"
android:text="Bas de page"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
|

Le rendu du layout contraint¶
Pour le layout précédent, le premier TextView doit avoir le haut au même niveau que le composant parent (c’est-à-dire le layout lui-même) et la bordure gauche doit également être au même niveau que le parent. On précise également une marge en haut et à gauche pour décoller le TextView.
Le second TextView a sa bordure gauche placée à droite du premier TextView.
Notez que le premier TextView est référencé par un id (@+id/textViewHello
)
et la ligne de texte est au même niveau (à la même hauteur) que la ligne de texte
du premier TextView. On applique à ce second TextView une marge à gauche. Donc
le layout doit positionner le second TextView exactement à droite du premier
avec un espacement de 5dp.
Enfin le troisième TextView doit avoir sa bordure du bas au même niveau que le bas du composant parent (c’est-à-dire le layout lui-même). De même, le début et la fin du TextView sont identiques au composant parent (c’est-à-dire le layout lui-même). Comme cela n’est pas possible car le taille du TextView est limité par son contenu, cela va avoir pour conséquence de centrer ce TextView. Enfin une marge du bas de 50dp est appliquée pour remonter légèrement vers le haut le composant.

Le rendu du layout contraint¶
Note
Pour explorer les possibilités du ConstraintLayout, vous pouvez vous reporter au tutoriel sur le site officiel :
Ajouter une image¶
La vue ImageView permet d’insérer une image dans une activité. Grâce à l’attribut
android:src
, vous spécifiez la source de l’image (par exemple un fichier PNG).
La source correspond à un identifiant de ressource de la forme @drawable/
suivi du nom du fichier image sans l’extension.
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/mon_image"/>
Note
Vous pouvez également référencer une ressource drawable avec l’attribut
android:background
pour positionner une image en arrière-plan d’une vue.
Une image PNG ou JPG est une image rastérisée (ou image matricielle). L’image est définie par une grille ou chaque point à une couleur. L’inconvénient de ce type d’images est qu’il s’adapte mal à des résolutions d’écran différentes.
Android supporte la possibilité de fournir plusieurs fois la même ressource en fonction du contexte d’exécution de l’application (par exemple de la résolution de l’écran). Pour une image, une application Android accepte plusieurs résolutions :
ldpi (low dots per inch) correspond à une image en 120 dpi.
mdpi (medium dots per inch) correspond à une image en 160 dpi.
hdpi (high dots per inch) correspond à une image en 240 dpi.
xhdpi (extra high dots per inch) correspond à une image en 320 dpi.
xxhdpi (extra extra high dots per inch) correspond à une image en 480 dpi.
xxxhdpi (extra extra extra high dots per inch) correspond à une image en 640 dpi.
Pour mémoire, vous pouvez utiliser un facteur multiplicateur de zoom pour connaître les dimensions nécessaires d’une image en prenant comme référence le mdpi. Chacune des images doit être placée dans un répertoire ressource comme indiqué ci-dessous. Chaque fichier image doit porter le même nom pour indiquer qu’il s’agit de la même ressource avec une résolution différente.
densité |
facteur de zoom |
répertoire |
---|---|---|
ldpi |
3/4 |
res/drawable-ldpi |
mdpi |
1 |
res/drawable-mdpi |
hdpi |
1,5 |
res/drawable-hdpi |
xhdpi |
2 |
res/drawable-xhdpi |
xxhdpi |
3 |
res/drawable-xxhdpi |
xxxhdpi |
4 |
res/drawable-xxxhdpi |
Vous devez créer ces répertoires dans votre projet et placer chaque image dans le bon répertoire.
Note
Avec ce système, vous pouvez définir quel fichier image utiliser en fonction
de la densité de l’écran. Cette utilisation conditionnelle d’une ressource
peut être étendue de manière générale avec la notion de qualifier. Un
qualifier est une condition ajoutée dans le nom du répertoire contenant
la ressource (comme par exemple res/drawable-ldpi
où -ldpi
est un qualifier).
L’utilisation de qualifier permet de fournir des ressources différentes en fonction de la langue, de l’orientation de l’écran, de la densité de l’écran, du type d’appareil… Pour en savoir plus, reportez-vous à la documentation officielle :
Exemple de formulaire¶
Une activité assez courante consiste à présenter un formulaire à l’utilisateur pour qu’il puisse saisir un ensemble d’informations. Ci-dessous, un exemple de layout avec son rendu :
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<EditText
android:id="@+id/prenom"
android:layout_margin="5sp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="textPersonName"
android:hint="Prénom"/>
<EditText
android:id="@+id/nom"
android:layout_margin="5sp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="textPersonName"
android:hint="Nom" />
<EditText
android:id="@+id/email"
android:layout_margin="5sp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="textEmailAddress"
android:hint="Email"/>
<EditText
android:id="@+id/naissance"
android:layout_margin="5sp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="date"
android:hint="Date de naissance JJ/MM/AAAA"/>
<EditText
android:id="@+id/description"
android:layout_margin="5sp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="textMultiLine"
android:hint="Description"
android:gravity="top"
android:height="200dp"/>
<EditText
android:id="@+id/commentaire"
android:layout_margin="5sp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:inputType="textMultiLine"
android:hint="Commentaire"
android:gravity="top"
android:height="200dp"/>
<CheckBox
android:id="@+id/acceptation_conditions"
android:layout_margin="5sp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Accepter les conditions d'utilisation" />
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_margin="5sp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="right">
<Button
android:id="@+id/bouton_annuler"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="handleAnnuler"
android:text="Annuler"/>
<Button
android:id="@+id/bouton_ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="handleOk"
android:text="Ok" />
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.appcompat.widget.LinearLayoutCompat>
</ScrollView>

Le rendu du formulaire¶
Notez l’utilisation de la ScrollView à la racine du layout pour permettre à l’utilisateur de faire défiler l’écran pour parcourir le formulaire. Ce layout utilise ensuite un LinearLayoutCompat vertical pour afficher chaque élément du formulaire. En dernier, il utilise un autre LinearLayoutCompat horizontal pour afficher les boutons côte-à-côte.
Le formulaire utilise des vues EditText en précisant, avec l’attribut
android:inputType
, le type du champ pour permettre au système de proposer
un type de saisie adapté au champ. L’utilisation de l’attribut android:hint
permet de préciser le rôle du champ sans avoir à ajouter de libellé de manière
à ne pas surcharger le formulaire.
Chaque champ de saisie, ainsi que chaque bouton, déclare un ID afin de pouvoir être identifié dans le code Java.
Pour traiter les données saisies par l’utilisateur, nous pouvons modifier l’implémentation de l’activité.
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 | package dev.gayerie.premiereapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.CheckBox;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private TextView nom;
private TextView prenom;
private TextView email;
private TextView naissance;
private TextView description;
private TextView commentaire;
private CheckBox acceptationConditions;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
nom = findViewById(R.id.nom);
prenom = findViewById(R.id.prenom);
email = findViewById(R.id.email);
naissance = findViewById(R.id.naissance);
description = findViewById(R.id.description);
commentaire = findViewById(R.id.commentaire);
acceptationConditions = findViewById(R.id.acceptation_conditions);
}
public void handleOk(View v) {
// TODO faire quelque chose de plus utile
Log.i(TAG, "Ok");
Log.i(TAG, String.format("Prénom : %s", prenom.getText()));
Log.i(TAG, String.format("Nom : %s", nom.getText()));
Log.i(TAG, String.format("Email : %s", email.getText()));
Log.i(TAG, String.format("Naissance : %s", naissance.getText()));
Log.i(TAG, String.format("Description : %s", description.getText()));
Log.i(TAG, String.format("Commentaire : %s", commentaire.getText()));
Log.i(TAG, String.format("Conditions acceptées : %b", acceptationConditions.isChecked()));
}
public void handleAnnuler(View v) {
// TODO faire quelque chose de plus utile
Log.i(TAG, "Annulé");
}
}
|
Dans la méthode onCreate
, à partir de la ligne 28, nous utilisons la méthode
findViewById pour récupérer chaque vue et la conserver dans un attribut.
Pour associer une action à chaque bouton, nous utilisons l’attribut android:onClick
dans le layout XML pour donner le nom d’une méthode de l’activité qui doit
être appelée. Cela évite de déclarer manuellement un listener dans le code
de l’activité (comme nous l’avons fait au chapitre précédent). La méthode de l’activité
doit être publique, ne retourner aucun résultat (void
) et prendre en
paramètre un objet de type View correspondant à l’objet cliqué. Nous déclarons
une méthode handleOk
pour l’associer au clic sur le bouton Ok et
une méthode handleAnnuler
pour l’associer au clic sur le bouton
Annuler.
Note
Dans cet exemple, en réaction au clic sur un bouton, nous nous contentons d’afficher des messages d’information dans les logs du système grâce à la classe Log.
À l’exécution de l’application, les logs sont accessibles depuis Android Studio dans l’onglet Logcat.
La barre d’action¶
La barre d’action est un composant habituel de la conception d’une interface mobile. Elle s’affiche en haut de l’écran et propose des actions contextuelles sous la forme d’icônes ou d’un menu.

Un exemple de barre d’action¶
Les boites de dialogue¶
Pour créer une boite de dialogue, vous pouvez utiliser la classe AlertDialog ainsi que la classe AlertDialog.Builder pour vous aider à créer votre boite de dialogue.
Boite de dialogue avec boutons¶
Dans une application Android, les boites de dialogue ont généralement un, deux
ou trois boutons désignés sous le terme de positif (par exemple ok), de neutre
(par exemple « plus tard ») et de négatif (par exemple « annuler »). Vous pouvez utiliser
la classe AlertDialog.Builder pour définir le titre, le message et les boutons
de la boite de dialogue et appeler ensuite la méthode show
pour présenter la
boite de dialogue. L’exemple ci-dessous présente du code qui peut être ajouté
dans une activité :
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 | public void afficherBoiteDeDialogue() {
DialogInterface.OnClickListener dialogListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
onClickBoiteDeDialogue(dialog, which);
}
};
new AlertDialog.Builder(this)
.setTitle("Ma boite")
.setMessage("Comment allez-vous ?")
.setPositiveButton("Bien", dialogListener)
.setNeutralButton("Ne sais pas", dialogListener)
.setNegativeButton("Pas super", dialogListener)
.show();
}
private void onClickBoiteDeDialogue(DialogInterface dialog, int which) {
switch (which) {
case AlertDialog.BUTTON_POSITIVE:
new AlertDialog.Builder(this).setMessage("Vous positivez !").show();
break;
case AlertDialog.BUTTON_NEUTRAL:
new AlertDialog.Builder(this).setMessage("Vous avez le droit de ne pas savoir.").show();
break;
case AlertDialog.BUTTON_NEGATIVE:
new AlertDialog.Builder(this).setMessage("Ça ne va pas fort !").show();
break;
}
}
|

Exemple d’une boite de dialogue avec des boutons¶

Exemple d’une boite de dialogue sans bouton¶
À la ligne 2, la méthode afficherBoiteDeDialogue
commence par déclarer un listener qui
implémente l’interface DialogInterface.OnClickListener. Cette interface ne
contient qu’une seule méthode qui est appelée lorsque l’utilisateur interagit
avec la boite de dialogue. Cette méthode reçoit en paramètre la boite de dialogue concernée
ainsi qu’un paramètre which
indiquant quel bouton a été cliqué. Dans cet
exemple, on se contente d’appeler une autre méthode onClickBoiteDeDialogue
qui
affiche elle-même une autre boite de dialogue sans bouton.
À la ligne 9, on affiche une boite de dialogue en précisant les différents
éléments (titre, message, boutons avec leur listener) pour finalement appeler
la méthode show()
. Notez que pour créer une instance de AlertDialog.Builder,
il faut passer en paramètre un contexte d’exécution Android. Une activité est
un contexte d’exécution. Si ces méthodes sont ajoutées au code d’une activité,
il suffit de passer this
en paramètre du constructeur.
Boite de dialogue avec choix¶
Un autre type de boite de dialogue assez courant consiste à permettre à l’utilisateur
de faire un choix dans une liste. Pour cela, il est possible d’utiliser la méthode
setItems
pour préciser la liste des choix (ou l’ID de la ressource correspondant
à un array). Comme pour les boutons, on associe un listener à la liste des
items. Le paramètre which reçu par la méthode onClick
correspond à l’index
du choix de l’utilisateur.
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 | public void afficherBoiteDeDialogue() {
DialogInterface.OnClickListener dialogListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
onClickBoiteDeDialogue(dialog, which);
}
};
String[] listeEtats = {"Bien", "Pas super", "Ne sais pas"};
new AlertDialog.Builder(this)
.setTitle("Mon autre boite")
.setItems(listeEtats, dialogListener)
.show();
}
private void onClickBoiteDeDialogue(DialogInterface dialog, int which) {
switch (which) {
case 0:
new AlertDialog.Builder(this).setMessage("Vous positivez !").show();
break;
case 1:
new AlertDialog.Builder(this).setMessage("Ça ne va pas fort !").show();
break;
case 2:
new AlertDialog.Builder(this).setMessage("Vous avez le droit de ne pas savoir.").show();
break;
}
}
|

Exemple d’une boite de dialogue avec une liste de choix¶
Note
Vous pouvez même concevoir une boite de dialogue avec n’importe quel
layout en utilisant la méthode setView
pour fournir un ID de ressource
de layout.
Message à l’utilisateur¶
Il est possible de faire apparaître brièvement un message à l’utilisateur pour confirmer un choix ou signaler un problème. Pour cela, vous pouvez utiliser soit la classe Toast soit la classe Snackbar (la seconde est recommandée pour un nouvelle application).
Toast¶
Toast.makeText(this, "Hello world", Toast.LENGTH_SHORT).show();
La méthode statique makeText permet de créer un message que l’on affiche
avec la méthode show()
. Comme premier paramètre, il faut passer un contexte
d’exécution Android. Si cette ligne est ajoutée au code d’une activité,
il suffit de passer this
en paramètre. Le second paramètre
est le texte à afficher et le troisième paramètre est une constante pour indiquer
la durée d’affichage du message (courte ou longue).

Affichage d’un toast¶
Snackbar¶
View content = findViewById(android.R.id.content);
Snackbar.make(content, "Hello world", Snackbar.LENGTH_LONG).show();
Le Snackbar fonctionne de manière très similaire au Toast. La méthode
statique make permet de créer le composant pour l’afficher avec la méthode
show()
. Le premier paramètre n’est pas un contexte d’exécution mais une vue
de l’activité. Dans l’exemple ci-dessus, on utilise le contenu de l’activité,
c’est-à-dire le layout pour créer le Snackbar. Le troisième paramètre est une
constante pour indiquer la durée d’affichage du message (courte ou longue).

Affichage d’un Snackbar¶
Note
Pour des cas plus complexes, notamment si l’utilisateur doit pouvoir réagir au message affiché, vous pouvez utiliser des notifications :