1. Avant de commencer
Dès le départ, Jetpack Compose a été conçu avec l'interopérabilité des vues. En d'autres termes, Compose et le système de vues peuvent partager des ressources et travailler ensemble pour afficher l'UI. Cette fonctionnalité vous permet d'ajouter Compose à une application existante basée sur les vues. Compose et les vues peuvent ainsi coexister dans votre codebase jusqu'à ce que votre application soit entièrement dans Compose.
Dans cet atelier de programmation, vous allez remplacer l'élément de liste basé sur les vues de l'application Juice Tracker par Compose. Si vous le souhaitez, vous pouvez convertir vous-même les autres vues de l'application Juice Tracker.
Si l'UI de votre application est basée sur les vues, vous préférerez peut-être la réécrire par étape plutôt qu'en une seule fois. Cet atelier de programmation vous aidera à convertir une vue unique d'une UI basée sur des vues en élément Compose.
Conditions préalables
- Vous devez maîtriser le concept d'UI basée sur les vues.
- Vous devez savoir créer une application à l'aide d'une UI basée sur les vues.
- Vous devez connaître la syntaxe du langage Kotlin, y compris les lambdas.
- Vous devez savoir créer une application dans Jetpack Compose.
Points abordés
- Ajouter Compose à un écran existant créé avec des vues Android
- Prévisualiser un composable ajouté à une application basée sur les vues
Objectifs de l'atelier
- Convertir un élément de liste basé sur une vue en élément Compose dans l'application Juice Tracker
2. Présentation de l'application de démarrage
Cet atelier de programmation utilise le code de solution de l'application Juice Tracker issue de la page Créer une application Android avec des vues comme code de démarrage. L'application de démarrage enregistre déjà les données à l'aide de la bibliothèque de persistance de Room. L'utilisateur peut ajouter des informations sur le jus de fruits à la base de données de l'application, comme son nom, sa description, sa couleur et sa note.
Dans cet atelier de programmation, vous allez convertir l'élément de liste basé sur une vue en élément Compose.
Télécharger le code de démarrage pour cet atelier de programmation
Pour commencer, téléchargez le code de démarrage :
Vous pouvez également cloner le dépôt GitHub du code :
$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-juice-tracker.git $ cd basic-android-kotlin-compose-training-juice-tracker $ git checkout views
Vous pouvez parcourir le code dans le dépôt GitHub JuiceTracker
.
3. Ajouter une bibliothèque Jetpack Compose
Compose et les vues peuvent coexister sur un même écran. En effet, vous pouvez avoir des éléments d'interface utilisateur dans Compose et d'autres dans le système de vues. Par exemple, vous pouvez choisir de n'utiliser que la liste dans Compose et de laisser le reste de l'écran dans le système de vues.
Suivez les étapes ci-dessous pour ajouter la bibliothèque Compose à l'application Juice Tracker.
- Ouvrez Juice Tracker dans Android Studio.
- Ouvrez le fichier
build.gradle.kts
au niveau de l'application. - Dans le bloc
buildFeatures
, ajoutez un indicateurcompose = true
.
buildFeatures {
//...
// Enable Jetpack Compose for this module
compose = true
}
Cet indicateur permet à Android Studio d'interagir avec Compose. Vous n'avez pas effectué cette étape dans les précédents ateliers de programmation, car Android Studio génère automatiquement ce code lorsque vous créez un projet de modèle Compose Android Studio.
- Sous
buildFeatures
, ajoutez le bloccomposeOptions
. - Dans le bloc, définissez
kotlinCompilerExtensionVersion
sur"1.5.1"
pour définir la version du compilateur Kotlin.
composeOptions {
kotlinCompilerExtensionVersion = "1.5.1"
}
- Dans la section
dependencies
, ajoutez des dépendances Compose. Vous devez disposer des dépendances suivantes pour ajouter Compose à une application basée sur des vues. Elles permettent d'intégrer Compose à l'activité, d'ajouter la bibliothèque de composants de conception Compose, d'accepter la thématisation Jetpack correspondante et de fournir des outils permettant une meilleure compatibilité avec l'IDE.
dependencies {
implementation(platform("androidx.compose:compose-bom:2023.06.01"))
// other dependencies
// Compose
implementation("androidx.activity:activity-compose:1.7.2")
implementation("androidx.compose.material3:material3")
implementation("com.google.accompanist:accompanist-themeadapter-material3:0.28.0")
debugImplementation("androidx.compose.ui:ui-tooling")
}
Ajouter ComposeView
Un ComposeView
est une vue Android pouvant héberger le contenu de l'UI de Jetpack Compose. Utilisez setContent
afin de fournir la fonction composable du contenu pour la vue.
- Ouvrez
layout/list_item.xml
et affichez l'aperçu dans l'onglet Split (Diviser).
À la fin de cet atelier de programmation, vous remplacerez cette vue par un composable.
- Dans
JuiceListAdapter.kt
, supprimezListItemBinding
de l'ensemble du code. Dans la classeJuiceListViewHolder
, remplacezbinding.root
parcomposeView
.
import androidx.compose.ui.platform.ComposeView
class JuiceListViewHolder(
private val onEdit: (Juice) -> Unit,
private val onDelete: (Juice) -> Unit
): RecyclerView.ViewHolder(composeView)
- Dans le dossier
onCreateViewHolder()
, mettez à jour la fonctionreturn()
pour qu'elle corresponde au code suivant :
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): JuiceListViewHolder {
return JuiceListViewHolder(
ComposeView(parent.context),
onEdit,
onDelete
)
}
- Dans la classe
JuiceListViewHolder
, supprimez toutes les variablesprivate
et l'intégralité du code de la fonctionbind()
. La classeJuiceListViewHolder
ressemble maintenant au code suivant :
class JuiceListViewHolder(
private val onEdit: (Juice) -> Unit,
private val onDelete: (Juice) -> Unit
) : RecyclerView.ViewHolder(composeView) {
fun bind(juice: Juice) {
}
}
- À ce stade, vous pouvez supprimer les importations
com.example.juicetracker.databinding.ListItemBinding
etandroid.view.LayoutInflater
.
// Delete
import com.example.juicetracker.databinding.ListItemBinding
import android.view.LayoutInflater
- Supprimez le fichier
layout/list_item.xml
. - Sélectionnez OK dans la boîte de dialogue Delete (Supprimer).
4. Ajouter une fonction composable
Ensuite, créez un composable qui émet l'élément de liste. Le composable nécessite Juice
et deux fonctions de rappel pour modifier et supprimer l'élément de liste.
- Dans
JuiceListAdapter.kt
, après la définition de la classeJuiceListAdapter
, créez une fonction composable nomméeListItem()
. - Faites en sorte que la fonction
ListItem()
accepte l'objetJuice
et un rappel lambda pour la suppression.
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
@Composable
fun ListItem(
input: Juice,
onDelete: (Juice) -> Unit,
modifier: Modifier = Modifier
) {
}
Examinez l'aperçu de l'élément de liste que vous souhaitez créer. Une icône de jus de fruits, des informations le concernant et un bouton de suppression sont également visibles. Vous allez bientôt implémenter ces composants.
Créer un composable pour l'icône de jus de fruits
- Dans
JuiceListAdapter.kt
, après le composableListItem()
, créez une autre fonction composable nomméeJuiceIcon()
, qui accepte uncolor
et unModifier
.
@Composable
fun JuiceIcon(color: String, modifier: Modifier = Modifier) {
}
- Dans la fonction
JuiceIcon()
, ajoutez des variables pourcolor
et la description du contenu, comme indiqué dans le code suivant :
@Composable
fun JuiceIcon(color: String, modifier: Modifier = Modifier) {
val colorLabelMap = JuiceColor.values().associateBy { stringResource(it.label) }
val selectedColor = colorLabelMap[color]?.let { Color(it.color) }
val juiceIconContentDescription = stringResource(R.string.juice_color, color)
}
Vous allez récupérer la ressource de couleur associée à la sélection de l'utilisateur à l'aide des variables colorLabelMap
et selectedColor
.
- Ajoutez une mise en page
Box
pour que les deux icônesic_juice_color
etic_juice_clear
se superposent. L'icôneic_juice_color
a une teinte et est centrée.
import androidx.compose.foundation.layout.Box
Box(
modifier.semantics {
contentDescription = juiceIconContentDescription
}
) {
Icon(
painter = painterResource(R.drawable.ic_juice_color),
contentDescription = null,
tint = selectedColor ?: Color.Red,
modifier = Modifier.align(Alignment.Center)
)
Icon(painter = painterResource(R.drawable.ic_juice_clear), contentDescription = null)
}
Comme vous connaissez bien l'implémentation de ce composable, vous ne trouverez pas ici de détails spécifiques sur la marche à suivre pour l'implémenter.
- Ajoutez une fonction pour afficher un aperçu de
JuiceIcon()
. Transmettez la couleur en tant queYellow
.
import androidx.compose.ui.tooling.preview.Preview
@Preview
@Composable
fun PreviewJuiceIcon() {
JuiceIcon("Yellow")
}
Créer des composables de détails sur les jus de fruits
Dans JuiceListAdapter.kt
, vous devez ajouter une autre fonction modulable pour afficher les détails du jus de fruits. Vous avez également besoin d'une mise en page en colonnes pour afficher deux composables Text
pour le nom et la description, ainsi qu'un indicateur d'évaluation. Pour ce faire, procédez comme suit :
- Ajoutez une fonction composable appelée
JuiceDetails()
qui reçoit un objetJuice
et unModifier
, ainsi qu'un composable de texte pour le nom du jus et un composable pour sa description, comme illustré dans le code suivant :
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.ui.text.font.FontWeight
@Composable
fun JuiceDetails(juice: Juice, modifier: Modifier = Modifier) {
Column(modifier, verticalArrangement = Arrangement.Top) {
Text(
text = juice.name,
style = MaterialTheme.typography.h5.copy(fontWeight = FontWeight.Bold),
)
Text(juice.description)
RatingDisplay(rating = juice.rating, modifier = Modifier.padding(top = 8.dp))
}
}
- Pour résoudre l'erreur de référence non résolue, créez une fonction composable nommée
RatingDisplay()
.
Le système de vues comprend un RatingBar
pour afficher la barre d'évaluation suivante. Compose n'a pas de composable pour la barre d'évaluation. Vous devez donc implémenter cet élément à partir de zéro.
- Définissez la fonction
RatingDisplay()
pour afficher les étoiles conformément à la note. Cette fonction composable affiche le nombre d'étoiles en fonction de la note.
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.pluralStringResource
@Composable
fun RatingDisplay(rating: Int, modifier: Modifier = Modifier) {
val displayDescription = pluralStringResource(R.plurals.number_of_stars, count = rating)
Row(
// Content description is added here to support accessibility
modifier.semantics {
contentDescription = displayDescription
}
) {
repeat(rating) {
// Star [contentDescription] is null as the image is for illustrative purpose
Image(
modifier = Modifier.size(32.dp),
painter = painterResource(R.drawable.star),
contentDescription = null
)
}
}
}
Pour créer le drawable "étoile" dans Compose, vous devez créer l'élément de vecteur d'étoile.
- Dans le volet Project (Projet), effectuez un clic droit sur drawable > New > Vector Asset (drawable > Nouveau > Élément vectoriel).
- Dans la boîte de dialogue Asset Studio, recherchez une icône en forme d'étoile. Sélectionnez l'icône d'étoile qui est remplie.
- Remplacez la valeur de la couleur de l'étoile par 625B71.
- Cliquez sur Next > Finish (Suivant > Terminer).
- Notez qu'un drawable apparaît dans le dossier
res/drawable
.
- Ajoutez un composable d'aperçu pour prévisualiser le composable
JuiceDetails
.
@Preview
@Composable
fun PreviewJuiceDetails() {
JuiceDetails(Juice(1, "Sweet Beet", "Apple, carrot, beet, and lemon", "Red", 4))
}
Créer un composable pour le bouton de suppression
- Dans
JuiceListAdapter.kt
, ajoutez une autre fonction composable appeléeDeleteButton()
qui utilise une fonction de rappel de lambdas et un modificateur. - Définissez le lambda sur l'argument
onClick
et transmettez l'Icon()
, comme indiqué dans le code suivant :
import androidx.compose.ui.res.painterResource
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
@Composable
fun DeleteButton(onDelete: () -> Unit, modifier: Modifier = Modifier) {
IconButton(
onClick = { onDelete() },
modifier = modifier
) {
Icon(
painter = painterResource(R.drawable.ic_delete),
contentDescription = stringResource(R.string.delete)
)
}
}
- Ajoutez une fonction d'aperçu pour prévisualiser le bouton de suppression.
@Preview
@Composable
fun PreviewDeleteIcon() {
DeleteButton({})
}
5. Implémenter la fonction ListItem
Maintenant que vous disposez de tous les composables requis pour afficher l'élément de liste, vous pouvez les organiser dans une mise en page. Notez la fonction ListItem()
que vous avez définie à l'étape précédente.
@Composable
fun ListItem(
input: Juice,
onEdit: (Juice) -> Unit,
onDelete: (Juice) -> Unit,
modifier: Modifier = Modifier
) {
}
Dans JuiceListAdapter.kt
, procédez comme suit pour implémenter la fonction ListItem()
:
- Ajoutez une mise en page
Row
dans le lambdaMdc3Theme {}
.
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import com.google.accompanist.themeadapter.material3.Mdc3Theme
Mdc3Theme {
Row(
modifier = modifier,
horizontalArrangement = Arrangement.SpaceBetween
) {
}
}
- Dans le lambda
Row
, appelez les trois composablesJuiceIcon
,JuiceDetails
etDeleteButton
que vous avez créés en tant qu'éléments enfants.
JuiceIcon(input.color)
JuiceDetails(input, Modifier.weight(1f))
DeleteButton({})
La transmission du Modifier.
weight
(1f)
au composable JuiceDetails()
garantit que les détails du jus de fruits occupent l'espace horizontal restant après la mesure des éléments enfants non pondérés.
- Transmettez le lambda et le modificateur
onDelete(input)
avec l'alignement en haut en tant que paramètres du composableDeleteButton
.
DeleteButton(
onDelete = {
onDelete(input)
},
modifier = Modifier.align(Alignment.Top)
)
- Écrivez une fonction d'aperçu pour prévisualiser le composable
ListItem
.
@Preview
@Composable
fun PreviewListItem() {
ListItem(Juice(1, "Sweet Beet", "Apple, carrot, beet, and lemon", "Red", 4), {})
}
- Liez le composable
ListItem
au conteneur de la vue. AppelezonEdit(input)
dans la fonction lambdaclickable()
pour ouvrir la boîte de dialogue de modification lorsque l'utilisateur clique sur l'élément de liste.
Dans la classe JuiceListViewHolder
et dans la fonction bind()
, vous devez héberger le composable. Utilisez ComposeView
, qui est une vue Android pouvant héberger le contenu de l'UI Compose à l'aide de sa méthode setContent
.
fun bind(input: Juice) {
composeView.setContent {
ListItem(
input,
onDelete,
modifier = Modifier
.fillMaxWidth()
.clickable {
onEdit(input)
}
.padding(vertical = 8.dp, horizontal = 16.dp),
)
}
}
- Exécutez l'application, puis ajoutez votre jus préféré. Notez l'élément de liste Compose qui brille.
.
Félicitations ! Vous venez de créer votre première application d'interopérabilité Compose, qui utilise des éléments Compose dans une application basée sur les vues.
6. 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-juice-tracker.git $ cd basic-android-kotlin-compose-training-juice-tracker $ git checkout views-with-compose
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.
7. En savoir plus
Documentation pour les développeurs Android
- Outils pour Compose | Jetpack Compose | Développeurs Android
- API d'interopérabilité | Jetpack Compose | Développeurs Android
- Stratégie de migration | Jetpack Compose | Développeurs Android
Atelier de programmation [intermédiaire]