1. Avant de commencer
Dans cet atelier de programmation, vous apprendrez à créer une liste déroulante dans votre application avec Jetpack Compose.
Vous utiliserez l'application Affirmations qui affiche une liste d'affirmations associées à de superbes images pour faire souffler un vent d'optimisme sur votre journée.
Les données existent déjà. Il vous suffit de les récupérer et de les afficher dans l'interface utilisateur.
Conditions préalables
- Vous maîtrisez les listes en Kotlin.
- Vous savez comment créer des mises en page avec Jetpack Compose.
- Vous savez comment exécuter des applications sur un appareil ou un émulateur.
Points abordés
- Créer une fiche Material Design à l'aide de Jetpack Compose.
- Créer une liste déroulante à l'aide de Jetpack Compose.
Objectifs de l'atelier
- Vous utiliserez une application existante et ajouterez une liste déroulante à l'interface utilisateur.
Le résultat final se présentera comme suit :
Ce dont vous avez besoin
- Un ordinateur avec accès à Internet, un navigateur Web et Android Studio
- Un accès à GitHub
Télécharger le code de démarrage
Dans Android Studio, ouvrez le dossier basic-android-kotlin-compose-training-affirmations
.
L'application doit afficher un écran vide lorsqu'elle est compilée à partir du code guichet starter
.
2. Créer une classe de données d'élément de liste
Créer une classe de données pour une affirmation
Dans les applications Android, les listes sont composées d'éléments. Pour les données individuelles, il peut s'agir d'éléments simples comme une chaîne ou un entier. Pour les éléments de liste qui contiennent divers types de données, comme une image et du texte, vous aurez besoin d'une classe contenant l'ensemble de ces propriétés. Une classe de données est un type qui ne contient que des propriétés. Elle peut fournir des méthodes utilitaires qui fonctionnent avec ces propriétés.
- Créez un package sous com.example.affirmations.
Nommez le nouveau package model. Le package "model" contient le modèle de données qui sera représenté par une classe de données. La classe de données comprend des propriétés qui représentent les informations correspondant à ce qui sera une "affirmation", à savoir une ressource de chaîne et une ressource d'image. Les packages sont des répertoires qui contiennent des classes et même d'autres répertoires.
- Créez une classe dans le package com.example.affirmations.model.
Nommez la nouvelle classe Affirmation et définissez-la en tant que Classe de données.
- Chaque
Affirmation
se compose d'une image et d'une chaîne. Créez deux propriétésval
dans la classe de donnéesAffirmation
. L'une doit être nomméestringResourceId
, et l'autreimageResourceId
. Dans les deux cas, il doit s'agir d'entiers.
Affirmation.kt
data class Affirmation(
val stringResourceId: Int,
val imageResourceId: Int
)
- Annotez la propriété
stringResourceId
avec l'annotation@StringRes
et annotezimageResourceId
avec l'annotation@DrawableRes
.stringResourceId
représente un ID du texte d'affirmation stocké dans une ressource de chaîne.imageResourceId
représente un ID de l'image d'affirmation stockée dans une ressource drawable.
Affirmation.kt
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
data class Affirmation(
@StringRes val stringResourceId: Int,
@DrawableRes val imageResourceId: Int
)
- Dans le package com.example.affirmations.data, ouvrez le fichier Datasource.kt et annulez la mise en commentaire des deux instructions d'importation et du contenu de la classe
Datasource
.
Datasource.kt
import com.example.affirmations.R
import com.example.affirmations.model.Affirmation
class Datasource() {
fun loadAffirmations(): List<Affirmation> {
return listOf<Affirmation>(
Affirmation(R.string.affirmation1, R.drawable.image1),
Affirmation(R.string.affirmation2, R.drawable.image2),
Affirmation(R.string.affirmation3, R.drawable.image3),
Affirmation(R.string.affirmation4, R.drawable.image4),
Affirmation(R.string.affirmation5, R.drawable.image5),
Affirmation(R.string.affirmation6, R.drawable.image6),
Affirmation(R.string.affirmation7, R.drawable.image7),
Affirmation(R.string.affirmation8, R.drawable.image8),
Affirmation(R.string.affirmation9, R.drawable.image9),
Affirmation(R.string.affirmation10, R.drawable.image10))
}
}
3. Ajouter une liste à votre application
Créer une vignette d'élément de liste
Cette application est destinée à afficher une liste d'affirmations. Lorsque vous configurez l'UI pour afficher une liste, la première étape consiste à créer un élément de liste. Chaque élément d'affirmation se compose d'une image et d'une chaîne. Les données de chacun de ces éléments sont fournies avec le code de démarrage. Vous créerez le composant d'interface utilisateur pour afficher ces éléments.
L'élément sera constitué d'un composable Card
contenant les composables Image
et Text
. Dans Compose, un élément Card
est une surface qui affiche du contenu et des actions dans un même conteneur. La vignette Affirmation se présentera comme suit dans l'aperçu :
La vignette affiche une image avec du texte en dessous. Cette mise en page verticale peut être obtenue à l'aide d'un composable Column
encapsulé dans un composable Card
. Pour parvenir à ce résultat, vous pouvez essayer par vous-même ou suivre les étapes ci-dessous.
- Ouvrez le fichier MainActivity.kt.
- Sous
AffirmationsApp()
, créez une méthode appeléeAffirmationCard()
et ajoutez-lui l'annotation@Composable
.
MainActivity.kt
@Composable
fun AffirmationsApp() {
}
@Composable
fun AffirmationCard() {
}
- Modifiez la signature de la méthode pour utiliser un objet
Affirmation
comme paramètre. L'objetAffirmation
provient du packagemodel
.
MainActivity.kt
import com.example.affirmations.model.Affirmation
@Composable
fun AffirmationCard(affirmation: Affirmation) {
}
- Ajoutez un paramètre
modifier
à la signature. Définissez la valeur par défautModifier
pour le paramètre.
MainActivity.kt
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
}
- Dans la méthode
AffirmationCard
, appelez le composableCard
. Transmettez le paramètremodifier
.
MainActivity.kt
import androidx.compose.material3.Card
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
Card(modifier = modifier) {
}
}
- Ajoutez un composable
Column
dans le composableCard
. Les éléments d'un composableColumn
sont organisés verticalement dans l'UI. Cela vous permet de placer une image au-dessus du texte associé. À l'inverse, un composableRow
organise les éléments qu'il contient horizontalement.
MainActivity.kt
import androidx.compose.foundation.layout.Column
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
Card(modifier = modifier) {
Column {
}
}
}
- Ajoutez un composable
Image
dans le corps lambda du composableColumn
. Rappelez-vous qu'un composableImage
doit toujours avoir une ressource à afficher, ainsi qu'uncontentDescription
. La ressource doit être un élémentpainterResource
transmis au paramètrepainter
. La méthodepainterResource
charge soit des drawables vectoriels, soit des formats d'élément rastérisés comme des fichiers PNG. Transmettez également un élémentstringResource
pour le paramètrecontentDescription
.
MainActivity.kt
import androidx.compose.foundation.Image
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
Card(modifier = modifier) {
Column {
Image(
painter = painterResource(affirmation.imageResourceId),
contentDescription = stringResource(affirmation.stringResourceId),
)
}
}
}
- En plus des paramètres
painter
etcontentDescription
, transmettez les élémentsmodifier
etcontentScale
.contentScale
détermine la manière dont l'image est mise à l'échelle et affichée. L'attributfillMaxWidth
de l'objetModifier
doit être défini et sa hauteur doit être de194.dp
.contentScale
doit être défini surContentScale.Crop
.
MainActivity.kt
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.ui.unit.dp
import androidx.compose.ui.layout.ContentScale
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
Card(modifier = modifier) {
Column {
Image(
painter = painterResource(affirmation.imageResourceId),
contentDescription = stringResource(affirmation.stringResourceId),
modifier = Modifier
.fillMaxWidth()
.height(194.dp),
contentScale = ContentScale.Crop
)
}
}
}
- Dans
Column
, créez un composableText
après le composableImage
. Transmettez un élémentstringResource
correspondant àaffirmation.stringResourceId
au paramètretext
, transmettez un objetModifier
avec l'attributpadding
défini sur16.dp
et définissez un thème de texte en transmettantMaterialTheme.typography.headlineSmall
au paramètrestyle
.
MainActivity.kt
import androidx.compose.material3.Text
import androidx.compose.foundation.layout.padding
import androidx.compose.ui.platform.LocalContext
@Composable
fun AffirmationCard(affirmation: Affirmation, modifier: Modifier = Modifier) {
Card(modifier = modifier) {
Column {
Image(
painter = painterResource(affirmation.imageResourceId),
contentDescription = stringResource(affirmation.stringResourceId),
modifier = Modifier
.fillMaxWidth()
.height(194.dp),
contentScale = ContentScale.Crop
)
Text(
text = LocalContext.current.getString(affirmation.stringResourceId),
modifier = Modifier.padding(16.dp),
style = MaterialTheme.typography.headlineSmall
)
}
}
}
Prévisualiser le composable AffirmationCard
La vignette est au cœur de l'interface utilisateur de l'application Affirmations, et vous avez travaillé dur pour la créer. Pour vous assurer que la vignette s'affiche correctement, vous pouvez créer un composable qui peut être prévisualisé sans lancer l'intégralité de l'application.
- Créez une méthode privée appelée
AffirmationCardPreview()
. Annotez la méthode avec@Preview
et@Composable
.
MainActivity.kt
import androidx.compose.ui.tooling.preview.Preview
@Preview
@Composable
private fun AffirmationCardPreview() {
}
- Dans cette méthode, appelez le composable
AffirmationCard
et transmettez-lui un nouvel objetAffirmation
avec la ressource de chaîneR.string.affirmation1
et la ressource drawableR.drawable.image1
transmise à son constructeur.
MainActivity.kt
@Preview
@Composable
private fun AffirmationCardPreview() {
AffirmationCard(Affirmation(R.string.affirmation1, R.drawable.image1))
}
- Ouvrez l'onglet Split (Diviser) pour afficher un aperçu de
AffirmationCard
. Si nécessaire, cliquez sur Build & Refresh (Compiler et actualiser) dans le volet Design (Conception) pour afficher l'aperçu.
Créer la liste
Le composant d'élément de liste est le composant principal d'une liste. Une fois l'élément de liste créé, vous pouvez l'exploiter pour créer le composant de liste proprement dit.
- Créez une fonction appelée
AffirmationList()
, ajoutez-lui l'annotation@Composable
et déclarez une liste (List
) d'objetsAffirmation
en tant que paramètre dans la signature de la méthode.
MainActivity.kt
@Composable
fun AffirmationList(affirmationList: List<Affirmation>) {
}
- Déclarez un objet
modifier
en tant que paramètre dans la signature de la méthode avec la valeur par défautModifier
.
MainActivity.kt
@Composable
fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
}
- Dans Jetpack Compose, une liste déroulante peut être créée à l'aide du composable
LazyColumn
. Un élémentLazyColumn
se différencie d'un élémentColumn
en ce sens queColumn
doit être utilisé lorsqu'il y a peu d'éléments à afficher, car Compose les charge tous en même temps. Un élémentColumn
ne peut contenir qu'un nombre prédéfini, ou fixe, de composables. Un élémentLazyColumn
peut ajouter du contenu à la demande. Cela convient pour les longues listes, en particulier lorsque la longueur de la liste est inconnue. Un élémentLazyColumn
accepte également le défilement par défaut, sans code supplémentaire. Déclarez un composableLazyColumn
dans la fonctionAffirmationList()
. Transmettez l'objetmodifier
en tant qu'argument àLazyColumn
.
MainActivity.kt
import androidx.compose.foundation.lazy.LazyColumn
@Composable
fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
LazyColumn(modifier = modifier) {
}
}
- Dans le corps lambda de
LazyColumn
, appelez la méthodeitems()
et transmettezaffirmationList
. La méthodeitems()
permet d'ajouter des éléments àLazyColumn
. Cette méthode est propre à ce composable. Il ne s'agit pas d'une pratique courante pour la plupart des composables.
MainActivity.kt
import androidx.compose.foundation.lazy.items
@Composable
fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
LazyColumn(modifier = modifier) {
items(affirmationList) {
}
}
}
- Une fonction lambda est requise pour appeler la méthode
items()
. Dans cette fonction, spécifiez un paramètreaffirmation
représentant un élément d'affirmation provenant de la propriétéaffirmationList
.
MainActivity.kt
@Composable
fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
LazyColumn(modifier = modifier) {
items(affirmationList) { affirmation ->
}
}
}
- Pour chaque affirmation de la liste, appelez le composable
AffirmationCard()
. Transmettez-lui l'objetaffirmation
et un objetModifier
avec l'attributpadding
défini sur8.dp
.
MainActivity.kt
@Composable
fun AffirmationList(affirmationList: List<Affirmation>, modifier: Modifier = Modifier) {
LazyColumn(modifier = modifier) {
items(affirmationList) { affirmation ->
AffirmationCard(
affirmation = affirmation,
modifier = Modifier.padding(8.dp)
)
}
}
}
Afficher la liste
- Dans le composable
AffirmationsApp
, récupérez les orientations de mise en page actuelles et enregistrez-les dans une variable. Elles seront utilisées pour configurer la marge intérieure ultérieurement.
MainActivity.kt
import com.example.affirmations.data.Datasource
@Composable
fun AffirmationsApp() {
val layoutDirection = LocalLayoutDirection.current
}
- À présent, créez un composable
Surface
. Ce composable définira la marge intérieure du composableAffirmationsList
.
MainActivity.kt
import com.example.affirmations.data.Datasource
@Composable
fun AffirmationsApp() {
val layoutDirection = LocalLayoutDirection.current
Surface() {
}
}
- Transmettez un
Modifier
au composableSurface
qui remplit la largeur et la hauteur maximales de son parent, définit la marge intérieure de la barre d'état et définit les marges intérieures de début et de fin surlayoutDirection
. Voici un exemple de conversion d'un objetLayoutDirection
en marge intérieure :WindowInsets.safeDrawing.asPaddingValues().calculateStartPadding(layoutDirection)
.
MainActivity.kt
import com.example.affirmations.data.Datasource
@Composable
fun AffirmationsApp() {
val layoutDirection = LocalLayoutDirection.current
Surface(
Modifier = Modifier
.fillMaxSize()
.statusBarsPadding()
.padding(
start = WindowInsets.safeDrawing.asPaddingValues()
.calculateStartPadding(layoutDirection),
end = WindowInsets.safeDrawing.asPaddingValues()
.calculateEndPadding(layoutDirection),
),
) {
}
}
- Dans le lambda du composable
Surface
, appelez le composableAffirmationList
et transmettezDataSource().loadAffirmations()
au paramètreaffirmationList
.
MainActivity.kt
import com.example.affirmations.data.Datasource
@Composable
fun AffirmationsApp() {
val layoutDirection = LocalLayoutDirection.current
Surface(
Modifier = Modifier
.fillMaxSize()
.statusBarsPadding()
.padding(
start = WindowInsets.safeDrawing.asPaddingValues()
.calculateStartPadding(layoutDirection),
end = WindowInsets.safeDrawing.asPaddingValues()
.calculateEndPadding(layoutDirection),
),
) {
AffirmationsList(
affirmationList = Datasource().loadAffirmations(),
)
}
}
Exécutez l'application Affirmations sur un appareil ou un émulateur pour voir le résultat final.
4. Télécharger le code de solution
Pour télécharger le code de cet atelier de programmation terminé, utilisez les commandes Git suivantes :
$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-affirmations.git $ cd basic-android-kotlin-compose-training-affirmations $ git checkout intermediate
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.
5. Conclusion
Vous savez maintenant comment créer des fiches, des éléments de liste et des listes déroulantes à l'aide de Jetpack Compose. Gardez à l'esprit qu'il ne s'agit que d'outils de base pour créer une liste. Vous pouvez laisser libre cours à votre créativité et personnaliser les éléments de la liste comme vous le souhaitez.
Résumé
- Utilisez des composables
Card
pour créer des éléments de liste. - Modifiez l'UI contenue dans un composable
Card
. - Créez une liste déroulante à l'aide du composable
LazyColumn
. - Créez une liste à l'aide d'éléments de liste personnalisés.