1. Avant de commencer
Introduction
À ce stade du cours, vous savez comment créer des applications avec Compose. Vous savez aussi comment créer des applications avec des fichiers XML, des vues, des liaisons de vue et des fragments. Après avoir conçu des applications basées sur des vues, vous avez peut-être trouvé intéressant de pouvoir créer ces mêmes applications avec une UI déclarative, comme Compose. Toutefois, dans certains cas, il est préférable d'utiliser des vues plutôt que Compose. Dans cet atelier de programmation, vous allez apprendre à avoir recours à l'interopérabilité des vues pour ajouter des composants de type "View" à une application Compose moderne.
Au moment de la rédaction de cet atelier de programmation, les composants d'UI que vous allez devoir créer ne sont pas encore disponibles dans Compose. C'est donc le moment idéal d'exploiter l'interopérabilité des vues.
Conditions préalables :
- Vous avez suivi le cours sur les principes de base d'Android dans Compose au sein de l'atelier de programmation Créer une application Android avec des vues.
Ce dont vous avez besoin
- Un ordinateur avec un accès à Internet et Android Studio
- Un appareil ou un émulateur
- Le code de démarrage de l'application Juice Tracker
Objectifs de l'atelier
Dans cet atelier de programmation, vous devrez intégrer trois vues dans l'UI de Compose pour terminer l'interface de l'application Juice Tracker : une roue de sélection des couleurs, une barre d'évaluation et une bannière publicitaire. Pour créer ces composants, vous devrez utiliser l'interopérabilité des vues. L'interopérabilité des vues vous permet d'ajouter des vues à votre application en les encapsulant dans un composable.
Tutoriel du code
Dans cet atelier de programmation, vous allez utiliser l'application Juice Tracker que vous avez utilisée pour les ateliers de programmation Créer une application Android avec des vues et Ajouter Compose à une application basée sur les vues. La différence avec cette version est que le code de démarrage fourni se trouve entièrement dans Compose. À ce stade, l'application ne permet pas d'indiquer la couleur ni les notes dans la boîte de dialogue de saisie, et elle n'affiche aucune bannière publicitaire en haut de l'écran de liste.
Le répertoire bottomsheet
contient tous les composants d'UI associés à la boîte de dialogue de saisie. Ce package devrait aussi contenir les composants d'UI permettant d'indiquer la couleur et la note, lorsqu'ils seront créés.
Le répertoire homescreen
contient les composants d'UI hébergés par l'écran d'accueil, y compris la liste JuiceTracker. À terme, ce package devrait aussi contenir la bannière publicitaire.
Les principaux composants d'UI, tels que la bottom sheet et la liste des jus, sont hébergés dans le fichier JuiceTrackerApp.kt
.
2. Télécharger le code de démarrage
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 compose-starter
- Dans Android Studio, ouvrez le dossier
basic-android-kotlin-compose-training-juice-tracker
. - Ouvrez le code de l'application Juice Tracker dans Android Studio.
3. Configuration de Gradle
Ajoutez la dépendance des annonces du service Play au fichier build.gradle.kts
de l'application.
app/build.gradle.kts
android {
...
dependencies {
...
implementation("com.google.android.gms:play-services-ads:22.2.0")
}
}
4. Configuration
Ajoutez la valeur suivante au fichier manifeste Android, au-dessus de la balise activity
, pour activer la bannière publicitaire à des fins de test :
AndroidManifest.xml
...
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="ca-app-pub-3940256099942544~3347511713" />
...
5. Terminer la boîte de dialogue de saisie
Dans cette section, vous allez terminer la boîte de dialogue de saisie en créant la roue de sélection des couleurs et la barre d'évaluation. La roue de sélection des couleurs est le composant qui vous permet de choisir une couleur, tandis que la barre d'évaluation vous permet de sélectionner une note pour le jus de fruits. Reportez-vous à la conception ci-dessous :
Créer la roue de sélection des couleurs
Pour implémenter une roue de sélection des couleurs dans Compose, vous devez utiliser la classe Spinner
. Spinner
est un composant View, et non un composable. Il doit donc être implémenté à l'aide d'une interopérabilité.
- Dans le répertoire
bottomsheet
, créez un fichier nomméColorSpinnerRow.kt
. - Dans le fichier nommé
SpinnerAdapter
, créez une classe. - Dans le constructeur de
SpinnerAdapter
, définissez un paramètre de rappel appeléonColorChange
qui utilise un paramètreInt
.SpinnerAdapter
gère les fonctions de rappel pour leSpinner
.
bottomsheet/ColorSpinnerRow.kt
class SpinnerAdapter(val onColorChange: (Int) -> Unit){
}
- Implémentez l'interface
AdapterView.OnItemSelectedListener
.
En implémentant cette interface, vous pouvez définir le comportement de clic pour la roue de sélection des couleurs. Vous configurerez cet adaptateur dans un composable ultérieurement.
bottomsheet/ColorSpinnerRow.kt
class SpinnerAdapter(val onColorChange: (Int) -> Unit): AdapterView.OnItemSelectedListener {
}
- Implémentez les fonctions membres
AdapterView.OnItemSelectedListener
:onItemSelected()
etonNothingSelected()
.
bottomsheet/ColorSpinnerRow.kt
class SpinnerAdapter(val onColorChange: (Int) -> Unit): AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
TODO("Not yet implemented")
}
override fun onNothingSelected(parent: AdapterView<*>?) {
TODO("Not yet implemented")
}
}
- Modifiez la fonction
onItemSelected()
pour qu'elle appelle la fonction de rappelonColorChange()
. De cette manière, lorsque vous sélectionnerez une couleur, l'application mettra à jour la valeur sélectionnée dans l'UI.
bottomsheet/ColorSpinnerRow.kt
class SpinnerAdapter(val onColorChange: (Int) -> Unit): AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
onColorChange(position)
}
override fun onNothingSelected(parent: AdapterView<*>?) {
TODO("Not yet implemented")
}
}
- Modifiez la fonction
onNothingSelected()
pour définir la couleur sur0
. Ainsi, lorsque vous ne sélectionnez rien, la couleur par défaut est la première (rouge).
bottomsheet/ColorSpinnerRow.kt
class SpinnerAdapter(val onColorChange: (Int) -> Unit): AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
onColorChange(position)
}
override fun onNothingSelected(parent: AdapterView<*>?) {
onColorChange(0)
}
}
Le SpinnerAdapter
, qui définit le comportement de la roue de sélection des couleurs via des fonctions de rappel, existe déjà. Vous devez maintenant créer le contenu de la roue de sélection des couleurs et y insérer des données.
- Dans le fichier
ColorSpinnerRow.kt
, mais en dehors de la classeSpinnerAdapter
, créez un composable appeléColorSpinnerRow
. - Dans la signature de la méthode
ColorSpinnerRow()
, ajoutez un paramètreInt
pour la position de la roue de sélection des couleurs, une fonction de rappel qui utilise un paramètreInt
et un modificateur.
bottomsheet/ColorSpinnerRow.kt
...
@Composable
fun ColorSpinnerRow(
colorSpinnerPosition: Int,
onColorChange: (Int) -> Unit,
modifier: Modifier = Modifier
) {
}
- Dans la fonction, créez un tableau avec les ressources de chaîne de couleurs de jus à l'aide de l'énumération
JuiceColor
. Ce tableau servira de contenu pour remplir la roue de sélection des couleurs.
bottomsheet/ColorSpinnerRow.kt
...
@Composable
fun ColorSpinnerRow(
colorSpinnerPosition: Int,
onColorChange: (Int) -> Unit,
modifier: Modifier = Modifier
) {
val juiceColorArray =
JuiceColor.values().map { juiceColor -> stringResource(juiceColor.label) }
}
- Ajoutez un composable
InputRow()
et transmettez la ressource de chaîne de couleurs pour le libellé d'entrée et un modificateur qui définit la ligne d'entrée où apparaît leSpinner
.
bottomsheet/ColorSpinnerRow.kt
...
@Composable
fun ColorSpinnerRow(
colorSpinnerPosition: Int,
onColorChange: (Int) -> Unit,
modifier: Modifier = Modifier
) {
val juiceColorArray =
JuiceColor.values().map { juiceColor -> stringResource(juiceColor.label) }
InputRow(inputLabel = stringResource(R.string.color), modifier = modifier) {
}
}
Vous allez maintenant créer le Spinner
. Comme Spinner
est une classe View, l'API d'interopérabilité des vues de Compose doit être utilisée pour l'encapsuler dans un composable. Pour ce faire, servez-vous du composable AndroidView
.
- Pour utiliser un
Spinner
dans Compose, créez un composableAndroidView()
dans le corps du lambdaInputRow
. Le composableAndroidView()
crée un élément ou une hiérarchie View dans un composable.
bottomsheet/ColorSpinnerRow.kt
...
@Composable
fun ColorSpinnerRow(
colorSpinnerPosition: Int,
onColorChange: (Int) -> Unit,
modifier: Modifier = Modifier
) {
val juiceColorArray =
JuiceColor.values().map { juiceColor -> stringResource(juiceColor.label) }
InputRow(inputLabel = stringResource(R.string.color), modifier = modifier) {
AndroidView()
}
}
Le composable AndroidView
utilise trois paramètres :
- Le lambda
factory
, qui est une fonction créant la vue - Le rappel
update
, qui est appelé lorsque la vue créée dans lefactory
est gonflée - Un composable
modifier
- Pour implémenter l'
AndroidView
, commencez par transmettre un modificateur et remplir la largeur maximale de l'écran. - Transmettez un lambda pour le paramètre
factory
. - Le lambda
factory
utiliseContext
comme paramètre. Créez une classeSpinner
et transmettez le contexte.
bottomsheet/ColorSpinnerRow.kt
...
@Composable
fun ColorSpinnerRow(
colorSpinnerPosition: Int,
onColorChange: (Int) -> Unit,
modifier: Modifier = Modifier
) {
...
InputRow(...) {
AndroidView(
modifier = Modifier.fillMaxWidth(),
factory = { context ->
Spinner(context)
}
)
}
}
Tout comme un RecyclerView.Adapter
fournit des données à un RecyclerView
, un ArrayAdapter
fournit des données à un Spinner
. Le Spinner
nécessite un adaptateur pour héberger le tableau de couleurs.
- Définissez l'adaptateur à l'aide d'un
ArrayAdapter
.ArrayAdapter
nécessite un contexte, une mise en page XML et un tableau. Transmettezsimple_spinner_dropdown_item
pour la mise en page. Cette mise en page est fournie par défaut avec Android.
bottomsheet/ColorSpinnerRow.kt
...
@Composable
fun ColorSpinnerRow(
colorSpinnerPosition: Int,
onColorChange: (Int) -> Unit,
modifier: Modifier = Modifier
) {
...
InputRow(...) {
AndroidView(
modifier = Modifier.fillMaxWidth(),
factory = { context ->
Spinner(context).apply {
adapter =
ArrayAdapter(
context,
android.R.layout.simple_spinner_dropdown_item,
juiceColorArray
)
}
}
)
}
}
Le rappel factory
renvoie une instance de la vue créée dans celle-ci. update
est un rappel qui accepte un paramètre du même type renvoyé par le rappel factory
. Ce paramètre est une instance de la vue qui est gonflée par le factory
. Dans ce cas, comme un Spinner
a été créé dans la fabrique, l'instance du Spinner
est accessible dans le corps du lambda update
.
- Ajoutez un rappel
update
qui transmet unspinner
. Utilisez le rappel fourni dans l'update
pour appeler la méthodesetSelection()
.
bottomsheet/ColorSpinnerRow.kt
...
@Composable
fun ColorSpinnerRow(
colorSpinnerPosition: Int,
onColorChange: (Int) -> Unit,
modifier: Modifier = Modifier
) {
...
InputRow(...) {
//...
},
update = { spinner ->
spinner.setSelection(colorSpinnerPosition)
spinner.onItemSelectedListener = SpinnerAdapter(onColorChange)
}
)
}
}
- Utilisez le
SpinnerAdapter
que vous avez créé précédemment pour définir un rappelonItemSelectedListener()
dans l'update
.
bottomsheet/ColorSpinnerRow.kt
...
@Composable
fun ColorSpinnerRow(
colorSpinnerPosition: Int,
onColorChange: (Int) -> Unit,
modifier: Modifier = Modifier
) {
...
InputRow(...) {
AndroidView(
// ...
},
update = { spinner ->
spinner.setSelection(colorSpinnerPosition)
spinner.onItemSelectedListener = SpinnerAdapter(onColorChange)
}
)
}
}
Le code de la roue de sélection des couleurs est maintenant terminé.
- Ajoutez la fonction utilitaire suivante pour obtenir l'index d'énumération
JuiceColor
. Vous l'utiliserez à l'étape suivante.
private fun findColorIndex(color: String): Int {
val juiceColor = JuiceColor.valueOf(color)
return JuiceColor.values().indexOf(juiceColor)
}
- Implémentez le
ColorSpinnerRow
dans le composableSheetForm
du fichierEntryBottomSheet.kt
. Placez la roue de sélection des couleurs après le texte "Description" et au-dessus des boutons.
bottomsheet/EntryBottomSheet.kt
...
@Composable
fun SheetForm(
juice: Juice,
onUpdateJuice: (Juice) -> Unit,
onCancel: () -> Unit,
onSubmit: () -> Unit,
modifier: Modifier = Modifier,
) {
...
TextInputRow(
inputLabel = stringResource(R.string.juice_description),
fieldValue = juice.description,
onValueChange = { description -> onUpdateJuice(juice.copy(description = description)) },
modifier = Modifier.fillMaxWidth()
)
ColorSpinnerRow(
colorSpinnerPosition = findColorIndex(juice.color),
onColorChange = { color ->
onUpdateJuice(juice.copy(color = JuiceColor.values()[color].name))
}
)
ButtonRow(
modifier = Modifier
.align(Alignment.End)
.padding(bottom = dimensionResource(R.dimen.padding_medium)),
onCancel = onCancel,
onSubmit = onSubmit,
submitButtonEnabled = juice.name.isNotEmpty()
)
}
}
Créer le composable de saisie de la note
- Créez un fichier appelé
RatingInputRow.kt
dans le répertoirebottomsheet
. - Dans le fichier
RatingInputRow.kt
, créez un composable appeléRatingInputRow()
. - Dans la signature de la méthode, transmettez un
Int
pour la note, un rappel avec un paramètreInt
afin de gérer un changement de sélection, ainsi qu'un modificateur.
bottomsheet/RatingInputRow.kt
@Composable
fun RatingInputRow(rating:Int, onRatingChange: (Int) -> Unit, modifier: Modifier = Modifier){
}
- Comme pour le
ColorSpinnerRow
, ajoutez unInputRow
au composable contenant unAndroidView
, tel qu'illustré dans l'exemple de code suivant.
bottomsheet/RatingInputRow.kt
@Composable
fun RatingInputRow(rating:Int, onRatingChange: (Int) -> Unit, modifier: Modifier = Modifier){
InputRow(inputLabel = stringResource(R.string.rating), modifier = modifier) {
AndroidView(
factory = {},
update = {}
)
}
}
- Dans le corps du lambda
factory
, créez une instance de la classeRatingBar
, qui fournit le type de barre d'évaluation nécessaire à cette conception. Définissez la valeurstepSize
sur1f
pour que la note ne puisse être qu'un nombre entier.
bottomsheet/RatingInputRow.kt
@Composable
fun RatingInputRow(rating:Int, onRatingChange: (Int) -> Unit, modifier: Modifier = Modifier){
InputRow(inputLabel = stringResource(R.string.rating), modifier = modifier) {
AndroidView(
factory = { context ->
RatingBar(context).apply {
stepSize = 1f
}
},
update = {}
)
}
}
Lorsque la vue sera gonflée, la note sera définie. Rappelez-vous que le factory
renvoie l'instance RatingBar
au rappel de mise à jour.
- Utilisez la note transmise au composable pour définir la note de l'instance
RatingBar
dans le corps du lambdaupdate
. - Lorsqu'une nouvelle note est définie, utilisez le rappel
RatingBar
pour appeler la fonction de rappelonRatingChange()
afin de mettre à jour la note dans l'UI.
bottomsheet/RatingInputRow.kt
@Composable
fun RatingInputRow(rating:Int, onRatingChange: (Int) -> Unit, modifier: Modifier = Modifier){
InputRow(inputLabel = stringResource(R.string.rating), modifier = modifier) {
AndroidView(
factory = { context ->
RatingBar(context).apply {
stepSize = 1f
}
},
update = { ratingBar ->
ratingBar.rating = rating.toFloat()
ratingBar.setOnRatingBarChangeListener { _, _, _ ->
onRatingChange(ratingBar.rating.toInt())
}
}
)
}
}
Le composable de saisie de la note est maintenant terminé.
- Utilisez le composable
RatingInputRow()
dans l'EntryBottomSheet
. Placez-le après la roue de sélection des couleurs et au-dessus des boutons.
bottomsheet/EntryBottomSheet.kt
@Composable
fun SheetForm(
juice: Juice,
onUpdateJuice: (Juice) -> Unit,
onCancel: () -> Unit,
onSubmit: () -> Unit,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(4.dp)
) {
...
ColorSpinnerRow(
colorSpinnerPosition = findColorIndex(juice.color),
onColorChange = { color ->
onUpdateJuice(juice.copy(color = JuiceColor.values()[color].name))
}
)
RatingInputRow(
rating = juice.rating,
onRatingChange = { rating -> onUpdateJuice(juice.copy(rating = rating)) }
)
ButtonRow(
modifier = Modifier.align(Alignment.CenterHorizontally),
onCancel = onCancel,
onSubmit = onSubmit,
submitButtonEnabled = juice.name.isNotEmpty()
)
}
}
Créer la bannière publicitaire
- Dans le package
homescreen
, créez un fichier appeléAdBanner.kt
. - Dans le fichier
AdBanner.kt
, créez un composable appeléAdBanner()
.
Contrairement aux composables précédents que vous avez créés, l'AdBanner
ne nécessite aucune entrée. Par conséquent, vous n'avez pas besoin de l'encapsuler dans un composable InputRow
. Toutefois, un AndroidView
est nécessaire.
- Essayez de créer la bannière vous-même à l'aide de la classe
AdView
. Assurez-vous de définir la taille d'annonce surAdSize.BANNER
et l'ID de bloc d'annonces sur"ca-app-pub-3940256099942544/6300978111"
. - En cas de gonflement de l'
AdView
, chargez une annonce en utilisant l'AdRequest Builder
.
homescreen/AdBanner.kt
@Composable
fun AdBanner(modifier: Modifier = Modifier) {
AndroidView(
modifier = modifier,
factory = { context ->
AdView(context).apply {
setAdSize(AdSize.BANNER)
// Use test ad unit ID
adUnitId = "ca-app-pub-3940256099942544/6300978111"
}
},
update = { adView ->
adView.loadAd(AdRequest.Builder().build())
}
)
}
- Placez l'
AdBanner
avant leJuiceTrackerList
dans leJuiceTrackerApp
. LeJuiceTrackerList
est déclaré à la ligne 83.
ui/JuiceTrackerApp.kt
...
AdBanner(
Modifier
.fillMaxWidth()
.padding(
top = dimensionResource(R.dimen.padding_medium),
bottom = dimensionResource(R.dimen.padding_small)
)
)
JuiceTrackerList(
juices = trackerState,
onDelete = { juice -> juiceTrackerViewModel.deleteJuice(juice) },
onUpdate = { juice ->
juiceTrackerViewModel.updateCurrentJuice(juice)
scope.launch {
bottomSheetScaffoldState.bottomSheetState.expand()
}
},
)
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 compose-with-views
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
8. Conclusion
Ce cours se termine ici, mais ce n'est que le début de votre parcours dans le développement d'applications Android !
Vous avez appris à créer des applications à l'aide de Jetpack Compose, un kit d'UI moderne permettant de concevoir des applications Android natives. Tout au long de ce cours, vous avez créé des applications avec des listes, avec un ou plusieurs écrans, et vous avez navigué entre leurs composants. Vous avez appris à concevoir des applications interactives, à faire en sorte qu'elles répondent aux entrées utilisateur et à mettre à jour l'UI. Vous avez appliqué Material Design et avez utilisé des couleurs, des formes et la typographie pour personnaliser votre application. Vous vous êtes également servi de Jetpack et d'autres bibliothèques tierces pour planifier des tâches, récupérer des données à partir de serveurs distants, les conserver en local et plus encore.
Grâce à ce cours, vous savez non seulement comment créer des applications attrayantes et responsives à l'aide de Jetpack Compose, mais vous disposez aussi des connaissances et des compétences nécessaires pour concevoir des applications Android efficaces, faciles à gérer et visuellement attrayantes. Ces principes de base vous aideront à continuer à développer vos compétences dans le domaine du Modern Android Development et de Compose.
Nous vous remercions d'avoir suivi et terminé ce cours. Nous encourageons chacun d'entre vous à poursuivre votre apprentissage et à vous perfectionner grâce à des ressources supplémentaires telles que la documentation pour les développeurs Android, le cours Jetpack Compose pour les développeurs Android, le document sur l'architecture moderne des applications Android, le blog des développeurs Android, d'autres ateliers de programmation ainsi que des exemples de projets.
Enfin, n'oubliez pas de partager ce que vous avez créé sur les réseaux sociaux et d'utiliser le hashtag #AndroidBasics pour que le reste de la communauté des développeurs Android et nous-mêmes puissions suivre votre évolution.
À vos claviers !