1. Avant de commencer
Dans cet atelier de programmation, vous allez créer l'application interactive Dice Roller, qui permet aux utilisateurs d'appuyer sur un composable Button
pour lancer un dé. Le résultat du lancer de dé sera affiché avec un composable Image
à l'écran.
Vous utiliserez Jetpack Compose avec Kotlin pour créer la mise en page de votre application, puis écrire la logique métier pour gérer le comportement qui se produira lorsque l'utilisateur appuiera sur le composable Button
.
Conditions préalables
- Vous êtes capable de créer et d'exécuter une application Compose de base dans Android Studio.
- Vous maîtrisez l'utilisation du composable
Text
dans une application. - Vous savez extraire du texte dans une ressource de chaîne pour faciliter la traduction de votre application et la réutilisation de chaînes.
- Vous disposez de connaissances de base en programmation Kotlin.
Points abordés
- Ajouter un composable
Button
à une application Android avec Compose - Ajouter un comportement à un composable
Button
dans une application Android avec Compose - Ouvrir et modifier le code
Activity
d'une application Android
Objectifs de l'atelier
- Créer une application Android interactive appelée Dice Roller, qui permettra aux utilisateurs de lancer un dé et affichera le résultat du lancer
Ce dont vous avez besoin
- Un ordinateur sur lequel est installé Android Studio
Voici à quoi ressemblera l'application à la fin de cet atelier de programmation :
2. Établir une référence
Créer un projet
- Dans Android Studio, cliquez sur File > New > New Project (Fichier > Nouveau > Nouveau projet).
- Dans la boîte de dialogue New Project (Nouveau projet), sélectionnez Empty Activity (Activité vide), puis cliquez sur Next (Suivant).
- Dans le champ Name (Nom), saisissez
Dice Roller
. - Dans le champ Minimum SDK (SDK minimal), sélectionnez un niveau d'API minimal de 24 (Nougat) dans le menu, puis cliquez sur Finish (Terminer).
3. Créer l'infrastructure de mise en page
Prévisualiser le projet
Pour prévisualiser le projet, procédez comme suit :
- Cliquez sur Build & Refresh (Compiler et actualiser) dans le volet Split (Diviser) ou Design (Conception).
Vous devriez maintenant voir un aperçu dans le volet Design (Conception). S'il semble petit, ne vous inquiétez pas, car il changera lorsque vous modifierez la mise en page.
Restructurer l'exemple de code
Vous devez modifier une partie du code généré pour qu'il ressemble davantage au thème d'une application de lancer de dé.
Comme vous l'avez vu dans la capture d'écran de l'application finale, l'image représente un dé avec un bouton qui permet de le lancer. Vous structurerez les fonctions composables de façon à refléter cette architecture.
Pour restructurer l'exemple de code, procédez comme suit :
- Supprimez la fonction
GreetingPreview()
. - Créez une fonction
DiceWithButtonAndImage()
avec l'annotation@Composable
.
Cette fonction composable représente les composants d'interface utilisateur de la mise en page. Elle contient également la logique du bouton cliquable et de l'affichage de l'image.
- Supprimez la fonction
Greeting(name: String, modifier: Modifier = Modifier)
. - Créez une fonction
DiceRollerApp()
avec les annotations@Preview
et@Composable
.
Comme cette application se compose uniquement d'un bouton et d'une image, considérez cette fonction composable comme l'application elle-même. C'est d'ailleurs pourquoi elle s'appelle DiceRollerApp()
.
MainActivity.kt
@Preview
@Composable
fun DiceRollerApp() {
}
@Composable
fun DiceWithButtonAndImage() {
}
Comme vous avez supprimé la fonction Greeting()
, l'appel de Greeting("Android")
dans le corps du lambda DiceRollerTheme()
est mis en évidence en rouge. Cela est dû au fait que le compilateur ne trouve plus de référence à cette fonction.
- Supprimez tout le code dans l'expression lambda
setContent{}
qui se trouve dans la méthodeonCreate()
. - Dans le corps de l'expression lambda
setContent{}
, appelez l'expression lambdaDiceRollerTheme{}
, puis, dans l'expression lambdaDiceRollerTheme{}
, appelez la fonctionDiceRollerApp()
.
MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
DiceRollerTheme {
DiceRollerApp()
}
}
}
- Dans la fonction
DiceRollerApp()
, appelez la fonctionDiceWithButtonAndImage()
.
MainActivity.kt
@Preview
@Composable
fun DiceRollerApp() {
DiceWithButtonAndImage()
}
Ajouter un modificateur
Compose utilise un objet Modifier
. Cet objet représente un ensemble d'éléments qui décorent ou modifient le comportement des éléments d'interface utilisateur Compose. Il vous permet de styliser les éléments d'interface utilisateur des composants de l'application Dice Roller.
Pour ajouter un modificateur, procédez comme suit :
- Modifiez la fonction
DiceWithButtonAndImage()
pour qu'elle accepte un argumentmodifier
de typeModifier
et attribuez-lui la valeur par défautModifier
.
MainActivity.kt
@Composable
fun DiceWithButtonAndImage(modifier: Modifier = Modifier) {
}
L'extrait de code précédent peut être déroutant. Examinons-le de plus près. La fonction autorise la transmission d'un paramètre modifier
. La valeur par défaut du paramètre modifier
est un objet Modifier
, ce qui explique la portion = Modifier
de la signature de la méthode. La valeur par défaut d'un paramètre permet à toute personne qui appellera cette méthode à l'avenir de décider de transmettre une valeur pour ce paramètre. Si cette personne transmet son propre objet Modifier
, elle peut personnaliser le comportement et la décoration de l'interface utilisateur. Si elle choisit de ne pas transmettre d'objet Modifier
, la valeur de l'objet par défaut, qui est l'objet Modifier
brut, sera alors déduite. Vous pouvez appliquer cette pratique à n'importe quel paramètre. Pour en savoir plus sur les arguments par défaut, consultez la section Arguments par défaut.
- Maintenant que le composable
DiceWithButtonAndImage()
possède un paramètre de modificateur, transmettez un modificateur lorsque le composable est appelé. Étant donné que la signature de la méthode pour la fonctionDiceWithButtonAndImage()
a été modifiée, un objetModifier
avec les décorations souhaitées devrait être transmis lors de son appel. La classeModifier
est responsable de la décoration ou de l'ajout d'un comportement à un composable dans la fonctionDiceRollerApp()
. Dans ce cas, vous devez ajouter des décorations importantes à l'objetModifier
transmis à la fonctionDiceWithButtonAndImage()
.
Vous vous interrogez peut-être sur l'intérêt de transmettre un argument Modifier
en présence d'un argument par défaut. La raison est la suivante : les composables peuvent faire l'objet d'une recomposition, ce qui signifie essentiellement que le bloc de code dans la méthode @Composable
s'exécute à nouveau. Si un objet Modifier
est créé dans un bloc de code, il peut être recréé, et cette méthode n'est pas efficace. La recomposition sera abordée ultérieurement dans cet atelier.
MainActivity.kt
DiceWithButtonAndImage(modifier = Modifier)
- Enchaînez une méthode
fillMaxSize()
au niveau de l'objetModifier
afin que la mise en page occupe la totalité de l'écran.
Cette méthode spécifie que les composants doivent occuper l'espace disponible. Plus tôt dans cet atelier, vous avez vu une capture d'écran de l'interface utilisateur finale de l'application Dice Roller. Une caractéristique notable est que le dé et le bouton sont au centre de l'écran. La méthode wrapContentSize()
indique que l'espace disponible doit être au moins aussi grand que les composants qu'il contient. Toutefois, comme la méthode fillMaxSize()
est utilisée, si les composants de la mise en page sont plus petits que l'espace disponible, un objet Alignment
peut être transmis à la méthode wrapContentSize()
, qui spécifie la façon dont les composants doivent s'aligner dans l'espace disponible.
MainActivity.kt
DiceWithButtonAndImage(modifier = Modifier
.fillMaxSize()
)
- Enchaînez la méthode
wrapContentSize()
au niveau de l'objetModifier
, puis transmettezAlignment.Center
en tant qu'argument pour centrer les composants.Alignment.Center
spécifie qu'un composant doit être centré verticalement et horizontalement.
MainActivity.kt
DiceWithButtonAndImage(modifier = Modifier
.fillMaxSize()
.wrapContentSize(Alignment.Center)
)
4. Créer une mise en page verticale
Dans Compose, les mises en page verticales sont créées avec la fonction Column()
.
La fonction Column()
est une mise en page composable qui place ses enfants dans une séquence verticale. Dans l'interface prévue de l'application, vous pouvez voir que l'image du dé s'affiche au-dessus du bouton permettant de le lancer :
Pour créer une mise en page verticale, procédez comme suit :
- Dans la fonction
DiceWithButtonAndImage()
, ajoutez une fonctionColumn()
.
- Transmettez l'argument
modifier
de la signature de la méthodeDiceWithButtonAndImage()
à l'argument de modificateur deColumn()
.
L'argument modifier
garantit que les composables de la fonction Column()
respectent les contraintes appelées sur l'instance modifier
.
- Transmettez un argument
horizontalAlignment
à la fonctionColumn()
, puis définissez-le sur la valeurAlignment.CenterHorizontally
.
De cette façon, les enfants compris dans la colonne seront centrés sur l'écran de l'appareil par rapport à la largeur.
MainActivity.kt
fun DiceWithButtonAndImage(modifier: Modifier = Modifier) {
Column (
modifier = modifier,
horizontalAlignment = Alignment.CenterHorizontally
) {}
}
5. Ajouter un bouton
- Dans le fichier
strings.xml
, ajoutez une chaîne et définissez-la sur la valeurRoll
.
res/values/strings.xml
<string name="roll">Roll</string>
- Dans le corps lambda de
Column()
, ajoutez une fonctionButton()
.
- Dans le fichier
MainActivity.kt
, ajoutez une fonctionText()
à l'élémentButton()
dans le corps lambda de la fonction. - Transmettez l'ID de ressource de la chaîne
roll
à la fonctionstringResource()
, puis transmettez le résultat au composableText
.
MainActivity.kt
Column(
modifier = modifier,
horizontalAlignment = Alignment.CenterHorizontally
) {
Button(onClick = { /*TODO*/ }) {
Text(stringResource(R.string.roll))
}
}
6. Insérer une image
L'image du dé est un élément essentiel de l'application. Elle affiche le résultat lorsque l'utilisateur appuie sur le bouton "Lancer". Vous ajouterez cette image avec un composable Image
, mais vous avez besoin d'une ressource d'image. Vous devrez donc d'abord télécharger les images fournies pour cette application.
Télécharger les images de dés
- Ouvrez cette URL pour télécharger un fichier ZIP d'images de dés sur votre ordinateur, puis attendez la fin du téléchargement.
Recherchez le fichier sur votre ordinateur. Il se trouve probablement dans le dossier Téléchargements.
- Décompressez le fichier ZIP pour créer un dossier
dice_images
contenant six fichiers image avec des valeurs de dé comprises entre 1 et 6.
Ajouter les images du dé à votre application
- Dans Android Studio, cliquez sur View > Tool Windows > Resource Manager (Afficher > Outils Windows > Gestionnaire de ressources).
- Cliquez sur + > Import Drawables (+ > Importer des drawables) pour ouvrir un explorateur de fichiers.
- Recherchez et sélectionnez le dossier contenant six images de dés, puis importez-les.
Les images importées se présenteront comme suit :
- Cliquez sur Suivant.
La boîte de dialogue Import drawables (Importer des drawables) s'affiche et indique l'emplacement des fichiers de ressources dans la structure de fichiers.
- Cliquez sur Import (Importer) pour confirmer que vous souhaitez importer les six images.
Les images doivent s'afficher dans le volet Resource Manager (Gestionnaire de ressources).
Bien joué ! Dans la tâche suivante, vous utiliserez ces images dans votre application.
Ajouter un composable Image
L'image du dé doit apparaître au-dessus du bouton "Lancer". Compose place les composants d'interface utilisateur de manière séquentielle. En d'autres termes, le composable déclaré en premier s'affiche en premier. Par exemple, la première déclaration s'affiche au-dessus ou avant le composable déclaré après. Les éléments d'un composable Column
s'affichent au-dessus et en dessous les uns des autres sur l'appareil. Dans cette application, vous utiliserez un élément Column
pour empiler des composables verticalement. Par conséquent, le composable déclaré en premier dans la fonction Column()
s'affiche avant le composable qui sera déclaré par la suite dans la même fonction Column()
.
Pour ajouter un composable Image
, procédez comme suit :
- Dans le corps de la fonction
Column()
, créez une fonctionImage()
avant la fonctionButton()
.
MainActivity.kt
Column(
modifier = modifier,
horizontalAlignment = Alignment.CenterHorizontally
) {
Image()
Button(onClick = { /*TODO*/ }) {
Text(stringResource(R.string.roll))
}
}
- Transmettez à la fonction
Image()
un argumentpainter
, puis attribuez-lui une valeurpainterResource
qui accepte un argument d'ID de ressource drawable. Pour l'instant, transmettez l'ID de ressource suivant : argumentR.drawable.dice_1
.
MainActivity.kt
Image(
painter = painterResource(R.drawable.dice_1)
)
- Chaque fois que vous créez une image dans votre application, vous devez fournir une "description de contenu". Les descriptions de contenu jouent un rôle important dans le développement Android. Elles sont associées à leurs composants d'interface utilisateur respectifs pour améliorer l'accessibilité. Pour en savoir plus sur les descriptions de contenu, consultez la section Décrire chaque élément d'interface utilisateur. Vous pouvez transmettre une description de contenu à l'image en tant que paramètre.
MainActivity.kt
Image(
painter = painterResource(R.drawable.dice_1),
contentDescription = "1"
)
Tous les composants d'interface utilisateur nécessaires sont désormais présents. Toutefois, les éléments Button
et Image
sont un peu trop proches l'un de l'autre.
- Pour résoudre ce problème, ajoutez un composable
Spacer
entre les élémentsImage
etButton
.Spacer
utilise un élémentModifier
comme paramètre. Dans ce cas,Image
est au-dessus deButton
. Il doit donc y avoir un espace vertical entre eux. Par conséquent, la hauteur deModifier
peut être définie pour s'appliquer àSpacer
. Essayez de définir une hauteur de16.dp
. En général, les dimensions en dp sont modifiées par incréments de4.dp
.
MainActivity.kt
Spacer(modifier = Modifier.height(16.dp))
- Dans le volet Preview (Aperçu), cliquez sur Build & Refresh (Compiler et actualiser).
Une image semblable à celle-ci devrait apparaître :
7. Créer la logique permettant de lancer les dés
Maintenant que tous les composables nécessaires sont présents, vous allez modifier l'application de sorte qu'un clic sur le bouton lance le dé.
Rendre le bouton interactif
- Dans la fonction
DiceWithButtonAndImage()
, avant la fonctionColumn()
, créez une variableresult
et attribuez-lui la valeur1
. - Examinez le composable
Button
. Vous remarquerez que le paramètreonClick
lui a été transmis ; ce paramètre est défini sur une paire d'accolades dans lesquelles se trouve le commentaire/*TODO*/
. Dans ce cas, les accolades représentent ce qu'on appelle une expression lambda, la zone à l'intérieur des accolades correspondant au corps de cette expression. Lorsqu'une fonction est transmise en tant qu'argument, elle peut également être appelée rappel.
MainActivity.kt
Button(onClick = { /*TODO*/ })
Une expression lambda est un littéral de fonction. C'est une fonction comme les autres, mais au lieu d'être déclarée séparément avec le mot clé fun
, elle est écrite de manière intégrée et transmise en tant qu'expression. Le composable Button
s'attend à ce qu'une fonction soit transmise en tant que paramètre onClick
. C'est l'endroit idéal pour utiliser une expression lambda. Dans cette section, vous écrirez le corps de cette expression.
- Dans la fonction
Button()
, supprimez le commentaire/*TODO*/
de la valeur du corps de l'expression lambda du paramètreonClick
. - Un lancer de dé est aléatoire. Pour refléter cette caractéristique dans le code, vous devez utiliser la syntaxe appropriée afin de générer un nombre aléatoire. En langage Kotlin, vous pouvez utiliser la méthode
random()
au niveau d'une plage de nombres. Dans le corps de l'expression lambdaonClick
, définissez la variableresult
sur une plage comprise entre 1 et 6, puis appelez la méthoderandom()
au niveau de cette plage. N'oubliez pas qu'en Kotlin, les plages sont désignées par deux points entre le premier chiffre de la plage et le dernier.
MainActivity.kt
fun DiceWithButtonAndImage(modifier: Modifier = Modifier) {
var result = 1
Column(
modifier = modifier,
horizontalAlignment = Alignment.CenterHorizontally
) {
Image(
painter = painterResource(R.drawable.dice_1),
contentDescription = "1"
)
Spacer(modifier = Modifier.height(16.dp))
Button(onClick = { result = (1..6).random() }) {
Text(stringResource(R.string.roll))
}
}
}
Il est désormais possible d'appuyer sur le bouton, mais cette action n'entraînera pas de changement visuel à ce stade, car vous devez encore créer cette fonctionnalité.
Ajouter une condition à l'application de lancer de dé
Dans la section précédente, vous avez créé une variable result
et l'avez codée en dur dans une valeur 1
. La valeur de la variable result
finira par être réinitialisée lorsque l'utilisateur appuiera sur le bouton "Lancer", ce qui devrait déterminer l'image à afficher.
Les composables sont sans état par défaut. En d'autres termes, ils ne contiennent pas de valeur et peuvent être recomposés à tout moment par le système, ce qui entraîne la réinitialisation de la valeur. Cependant, Compose offre un moyen pratique d'éviter cela. Les fonctions composables peuvent stocker un objet en mémoire à l'aide du composable remember
.
- Convertissez la variable
result
en composableremember
.
Le composable remember
nécessite la transmission d'une fonction.
- Dans le corps du composable
remember
, transmettez une fonctionmutableStateOf()
, puis transmettez-lui un argument1
.
La fonction mutableStateOf()
renvoie un objet observable. Vous vous familiariserez avec les objets observables par la suite. Pour l'instant, rappelez-vous juste que lorsque la valeur de la variable result
change, une recomposition est déclenchée, la valeur du résultat est reflétée et l'interface utilisateur est actualisée.
MainActivity.kt
var result by remember { mutableStateOf(1) }
Désormais, lorsque l'utilisateur appuie sur le bouton, la variable result
est mise à jour avec une valeur aléatoire.
Vous pouvez maintenant utiliser la variable result
pour déterminer l'image à afficher.
- Sous l'instanciation de la variable
result
, créez une variableimageResource
immuable définie sur une expressionwhen
qui accepte une variableresult
, puis définissez chaque résultat possible sur son drawable.
MainActivity.kt
val imageResource = when (result) {
1 -> R.drawable.dice_1
2 -> R.drawable.dice_2
3 -> R.drawable.dice_3
4 -> R.drawable.dice_4
5 -> R.drawable.dice_5
else -> R.drawable.dice_6
}
- Remplacez l'ID transmis au paramètre
painterResource
du composableImage
à partir du drawableR.drawable.dice_1
par la variableimageResource
. - Modifiez le paramètre
contentDescription
du composableImage
pour refléter la valeur de la variableresult
en convertissant la variableresult
en chaîne avectoString()
et en la transmettant en tant quecontentDescription
.
MainActivity.kt
Image(
painter = painterResource(imageResource),
contentDescription = result.toString()
)
- Exécutez votre application.
Votre application de lancer de dé devrait maintenant fonctionner correctement.
8. Télécharger le code de solution
Pour télécharger le code de l'atelier de programmation terminé, utilisez la commande Git suivante :
$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-dice-roller.git
Vous pouvez également télécharger le dépôt sous forme de fichier ZIP, le décompresser et l'ouvrir dans Android Studio.
Si vous souhaitez voir le code de solution, affichez-le sur GitHub.
- Accédez à la page du dépôt GitHub fournie pour le projet.
- Vérifiez que le nom de la branche correspond à celui spécifié dans l'atelier de programmation. Par exemple, dans la capture d'écran suivante, le nom de la branche est main.
- Sur la page GitHub du projet, cliquez sur le bouton Code pour afficher une fenêtre pop-up.
- Dans la fenêtre pop-up, cliquez sur le bouton Download ZIP (Télécharger le fichier ZIP) pour enregistrer le projet sur votre ordinateur. Attendez la fin du téléchargement.
- Recherchez le fichier sur votre ordinateur (il se trouve probablement dans le dossier Téléchargements).
- Double-cliquez sur le fichier ZIP pour le décompresser. Un dossier contenant les fichiers du projet est alors créé.
Ouvrir le projet dans Android Studio
- Lancez Android Studio.
- Dans la fenêtre Welcome to Android Studio (Bienvenue dans Android Studio), cliquez sur Open (Ouvrir).
Remarque : Si Android Studio est déjà ouvert, sélectionnez l'option de menu File > Open (Fichier > Ouvrir).
- Dans l'explorateur de fichiers, accédez à l'emplacement du dossier du projet décompressé (il se trouve probablement dans le dossier Téléchargements).
- Double-cliquez sur le dossier de ce projet.
- Attendez qu'Android Studio ouvre le projet.
- Cliquez sur le bouton Run (Exécuter) pour compiler et exécuter l'application. Assurez-vous qu'elle fonctionne correctement.
9. Conclusion
Vous avez utilisé Compose pour créer une application interactive de lancer de dé, intitulée Dice Roller, pour Android.
Résumé
- Définissez des fonctions composables.
- Créez des mises en page avec des compositions.
- Créez un bouton avec le composable
Button
. - Importez des ressources
drawable
. - Affichez une image avec le composable
Image
. - Créez une UI interactive avec des composables.
- Utilisez le composable
remember
pour stocker en mémoire les objets d'une composition. - Actualisez l'UI avec la fonction
mutableStateOf()
pour créer un objet observable.