Calculer un pourboire personnalisé

1. Avant de commencer

Dans cet atelier de programmation, vous utiliserez le code de solution de l'atelier de programmation Présentation de l'état dans Compose afin de créer une calculatrice de pourboire interactive. Celle-ci permettra de calculer et d'arrondir automatiquement le montant d'un pourboire lorsque vous saisissez le montant de la note et le pourcentage de pourboire. Cette image représente l'application finale :

24370de6d667a700.png

Conditions préalables

  • Vous avez suivi l'atelier de programmation sur l'utilisation de l'état dans Jetpack Compose.
  • Vous êtes capable d'ajouter des composables Text et TextField à une application.
  • Vous connaissez la fonction remember, l'état, le hissage d'état et la différence entre les fonctions modulables avec état et les fonctions modulables sans état.

Points abordés

  • Ajouter un bouton d'action à un clavier virtuel
  • Configurer les actions du clavier
  • Définition et mode de fonctionnement d'un composable Switch
  • Présentation de l'outil d'inspection de la mise en page

Objectifs de l'atelier

  • Création d'une application intitulée Tip Time permettant de calculer le montant d'un pourboire en fonction du coût de service saisi par l'utilisateur et du pourcentage de pourboire.

Ce dont vous avez besoin

  • Android Studio
  • Code de solution de l'atelier sur l'utilisation de l'état dans Jetpack Compose

2. Présentation de l'application de démarrage

Cet atelier de programmation commence avec l'application Tip Time issue de l'atelier de programmation précédent. Il fournit l'interface utilisateur nécessaire pour calculer un pourboire avec un pourcentage fixe. La zone de texte Coût du service permet à l'utilisateur de saisir le coût du service. L'application calcule et affiche le montant du pourboire dans un composable Text.

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 pour obtenir le code :

$ git clone https://github.com/google-developer-training/basic-android-kotlin-compose-training-tip-calculator.git
$ cd basic-android-kotlin-compose-training-tip-calculator
$ git checkout state

Vous pouvez parcourir le code dans le dépôt GitHub Tip Calculator.

Exécuter l'application Tip Time

  1. Ouvrez le projet Tip Time dans Android Studio, puis exécutez l'application sur un émulateur ou un appareil.
  2. Saisissez un coût de service. L'application calcule et affiche automatiquement le montant du pourboire.

761df483de663721.png

Dans la configuration actuelle, le pourcentage de pourboire est codé en dur et se monte à 15 %. Dans cet atelier de programmation, vous ajouterez à cette fonctionnalité un champ de texte permettant à l'application de calculer un pourcentage de pourboire personnalisé et d'arrondir son montant.

Ajouter les ressources de chaîne nécessaires

  1. Dans l'onglet Projet, cliquez sur res > values > string.xml.
  2. Entre les balises <resources> du fichier strings.xml, ajoutez les ressources de chaîne suivantes :
<string name="how_was_the_service">Tip (%)</string>
<string name="round_up_tip">Round up tip?</string>

Le fichier strings.xml doit ressembler à cet extrait de code, qui inclut les chaînes de l'atelier de programmation précédent :

strings.xml

<resources>
   <string name="app_name">TipTime</string>
   <string name="calculate_tip">Calculate Tip</string>
   <string name="cost_of_service">Cost of Service</string>
   <string name="how_was_the_service">Tip (%)</string>
   <string name="round_up_tip">Round up tip?</string>
   <string name="tip_amount">Tip Amount: %s</string>
</resources>
  1. Remplacez la chaîne Cost Of Service par une chaîne Bill Amount. Dans certains pays, le terme service signifie pourboire. Cette modification évite donc toute confusion.
  2. Dans la chaîne Cost of Service, effectuez un clic droit sur le nom (name) cost_of_service de l'attribut, puis sélectionnez Refactor > Rename (Refactoriser > Renommer). Une boîte de dialogue Renommer s'ouvre.

a2f301b95a8c0e3f.png

  1. Dans la boîte de dialogue Rename (Renommer), remplacez cost_of _service par bill_amount et cliquez sur Refactor (Refactoriser). Toutes les occurrences de la ressource de chaîne cost_of_service sont mises à jour dans le projet. Vous n'avez donc pas besoin de modifier le code Compose manuellement.

f525a371c2851d08.png

  1. Dans le fichier strings.xml, remplacez la valeur de chaîne Cost of Service par Bill Amount :
<string name="bill_amount">Bill Amount</string>
  1. Accédez au fichier MainActivity.kt, puis exécutez l'application. Le libellé est mis à jour dans la zone de texte, comme illustré dans cette image :

champ de texte affichant le montant de la facture au lieu du coût du service

3. Ajouter un champ de texte pour le pourcentage de pourboire

Le pourboire peut être plus ou moins élevé en fonction de la qualité du service fourni et d'autres raisons. C'est pourquoi l'application doit permettre à l'utilisateur de calculer un pourboire personnalisé. Dans cette section, vous ajouterez un champ de texte dans lequel l'utilisateur pourra saisir un pourcentage de pourboire personnalisé, comme illustré dans l'image ci-dessous :

47b5e8543e5eb754.png

Vous disposez déjà d'un composable de champ de texte Montant de la facture dans votre application, qui est la fonction modulable EditNumberField() sans état. Dans l'atelier de programmation précédent, vous avez hissé l'état amountInput du composable EditNumberField() vers la fonction TipTimeScreen(). C'est pour cela que le composable EditNumberField() est devenu sans état.

Pour ajouter un champ de texte, vous pouvez réutiliser le même composable EditNumberField(), mais avec un libellé différent. Pour effectuer cette modification, vous devez transmettre le libellé en tant que paramètre plutôt que de le coder en dur dans la fonction modulable EditNumberField().

Rendez la fonction modulable EditNumberField() réutilisable :

  1. Dans le fichier MainActivity.kt dans les paramètres de la fonction modulable EditNumberField(), ajoutez une ressource de chaîne label de type Int :
@Composable
fun EditNumberField(
   label: Int,
   value: String,
   onValueChange: (String) -> Unit
) 
  1. Ajoutez un argument modifier de type Modifier à la fonction modulable EditNumberField() :
@Composable
fun EditNumberField(
   label: Int,
   value: String,
   onValueChange: (String) -> Unit,
   modifier: Modifier = Modifier
) 
  1. Dans le corps de la fonction, remplacez l'ID de ressource de la chaîne codée en dur par le paramètre label :
@Composable
fun EditNumberField(
   //...
) {
   TextField(
       //...
       label = { Text(stringResource(label)) },
       //...
   )
}
  1. Pour indiquer que le paramètre label doit être une référence de ressource de chaîne, annotez le paramètre de fonction avec la mention @StringRes :
@Composable
fun EditNumberField(
   @StringRes label: Int,
   value: String,
   onValueChange: (String) -> Unit,
   modifier: Modifier = Modifier
) 
  1. Exécutez la commande d'importation suivante :
import androidx.annotation.StringRes
  1. Dans le composable TextField de la fonction EditNumberField(), transmettez le paramètre label à la fonction stringResource().
@Composable
fun EditNumberField(
   @StringRes label: Int,
   value: String,
   onValueChange: (String) -> Unit,
   modifier: Modifier = Modifier
) {
   TextField(
       //...
       label = { Text(stringResource(label)) },
       //...
   )
} 
  1. Dans l'appel EditNumberField() de la fonction TipTimeScreen(), définissez le paramètre label sur la ressource de chaîne R.string.bill_amount :
EditNumberField(
   label = R.string.bill_amount,
   value = amountInput,
   onValueChange = { amountInput = it }
)
  1. Dans le volet "Design" (Conception), cliquez sur 2d40b921003ab5eb.png Build & Refresh (Compiler et actualiser). L'UI de l'application devrait se présenter comme suit :

a84cd50c50235a9f.png

  1. Dans la fonction TipTimeScreen() après l'appel de EditNumberField(), ajoutez un autre champ de texte pour le pourcentage de pourboire personnalisé. Appelez la fonction modulable EditNumberField() avec les paramètres suivants :
EditNumberField(
   label = R.string.how_was_the_service,
   value = "",
   onValueChange = { }
)

Une zone de texte supplémentaire est ajoutée pour le pourcentage de pourboire personnalisé.

  1. Dans le volet "Design" (Conception), cliquez sur 2d40b921003ab5eb.png Build & Refresh (Compiler et actualiser). L'aperçu de l'application affiche désormais un champ de texte Pourboire (%), comme illustré sur cette image :

9d2c01d577d077ae.png

  1. En haut de la fonction TipTimeScreen(), ajoutez une propriété var appelée tipInput pour la variable d'état du champ de texte ajouté. Utilisez mutableStateOf("") pour initialiser la variable et délimitez l'appel avec la fonction remember :
var tipInput by remember { mutableStateOf("") }
  1. Dans le nouvel appel de fonction EditNumberField(), définissez le paramètrevalue sur la variable tipInput, puis mettez à jour la variable tipInput dans l'expression lambda onValueChange :
EditNumberField(
   label = R.string.how_was_the_service,
   value = tipInput,
   onValueChange = { tipInput = it }
)
  1. Dans la fonction TipTimeScreen(), après la définition de la variable tipInput, définissez une variable val nommée tipPercent qui convertit la variable tipInput en un type Double, utilisez un opérateur Elvis et renvoyez 0.0 si la valeur est null :
val tipPercent = tipInput.toDoubleOrNull() ?: 0.0
  1. Dans la fonction TipTimeScreen(), mettez à jour l'appel de fonction calculateTip() et transmettez la variable tipPercent en tant que deuxième paramètre :
val tip = calculateTip(amount, tipPercent)

Le code de la fonction TipTimeScreen() devrait maintenant ressembler à cet extrait de code :

@Composable
fun TipTimeScreen() {
   var amountInput by remember { mutableStateOf("") }
   var tipInput by remember { mutableStateOf("") }

   val tipPercent = tipInput.toDoubleOrNull() ?: 0.0
   val amount = amountInput.toDoubleOrNull() ?: 0.0
   val tip = calculateTip(amount, tipPercent)

   Column(
       modifier = Modifier.padding(32.dp),
       verticalArrangement = Arrangement.spacedBy(8.dp)
   ) {
       Text(
           text = stringResource(R.string.calculate_tip),
           fontSize = 24.sp,
           modifier = Modifier.align(Alignment.CenterHorizontally)
       )
       Spacer(Modifier.height(16.dp))
       EditNumberField(
           label = R.string.bill_amount,
           value = amountInput,
           onValueChange = { amountInput = it }
       )
       EditNumberField(
           label = R.string.how_was_the_service,
           value = tipInput,
           onValueChange = { tipInput = it }
       )
       Spacer(Modifier.height(24.dp))
       Text(
           text = stringResource(R.string.tip_amount, tip),
           modifier = Modifier.align(Alignment.CenterHorizontally),
           fontSize = 20.sp,
           fontWeight = FontWeight.Bold
       )
   }
}
  1. Exécutez l'application sur un émulateur ou un appareil, puis saisissez le montant de la facture et le pourcentage de pourboire. L'application calcule-t-elle correctement le montant du pourboire ?

bdc482b015472300.png

4. Définir un bouton d'action

Dans l'atelier de programmation précédent, vous avez appris à utiliser la classe KeyboardOptions pour définir le type de clavier. Dans cette section, vous allez découvrir comment définir le bouton d'action du clavier avec la même classe, KeyboardOptions. Un bouton d'action est un bouton situé à l'extrémité du clavier. Voici quelques exemples dans ce tableau :

Propriété

Bouton d'action du clavier

ImeAction.SearchOption possible lorsque l'utilisateur souhaite effectuer une recherche.

ImeAction.SendOption possible lorsque l'utilisateur souhaite envoyer le texte dans le champ de saisie.

ImeAction.GoOption possible lorsque l'utilisateur souhaite accéder à la cible du texte dans l'entrée.

Au cours de cette tâche, vous définirez deux boutons d'action différents pour les zones de texte :

  • Un bouton d'action Next (Suivant) pour la zone de texte Montant de la facture, qui indique que l'utilisateur a terminé la saisie et souhaite passer à la zone de texte suivante.
  • Un bouton d'action Terminé pour la zone de texte Pourcentage de pourboire, qui indique que l'utilisateur a terminé de saisir une entrée.

Voici, dans les images ci-dessous, des exemples de claviers comportant ces boutons d'action :

Ajouter des options de clavier :

  1. Dans l'appel TextField() de la fonction EditNumberField(), transmettez au constructeur KeyboardOptions un argument nommé imeAction défini sur une valeur ImeAction.Next. Appelez la fonction KeyboardOptions.Default.copy pour utiliser d'autres options par défaut, comme l'utilisation appropriée des majuscules et la correction automatique.
@Composable
fun EditNumberField(
   //...
) {
   TextField(
       //...
       keyboardOptions = KeyboardOptions.Default.copy(
           keyboardType = KeyboardType.Number,
           imeAction = ImeAction.Next
       )
   )
}
  1. Exécutez l'application sur un émulateur ou un appareil. Le clavier affiche maintenant le bouton d'action Suivant, comme illustré sur cette image :

Toutefois, vous avez besoin de deux boutons d'action différents pour les champs de texte. Vous allez rapidement résoudre ce problème.

  1. Examinez la fonction EditNumberField(). Le paramètre keyboardOptions de la fonction TextField() est codé en dur. Pour créer différents boutons d'action pour les champs de texte, vous devez transmettre l'objet KeyboardOptions en tant qu'argument, ce que vous ferez à l'étape suivante.
// No need to copy, just examine the code.
fun EditNumberField(
   @StringRes label: Int,
   value: String,
   onValueChange: (String) -> Unit
) {
   TextField(
       //...
       keyboardOptions = KeyboardOptions.Default.copy(
          keyboardType = KeyboardType.Number,
          imeAction = ImeAction.Next
       )
   )
}
  1. Dans la définition de la fonction EditNumberField(), ajoutez un paramètre keyboardOptions de type KeyboardOptions. Dans le corps de la fonction, attribuez-le au paramètre nommé keyboardOptions de la fonction TextField() :
@Composable
fun EditNumberField(
   @StringRes label: Int,
   keyboardOptions: KeyboardOptions,
   value: String,
   onValueChange: (String) -> Unit
){
   TextField(
       //...
       keyboardOptions = keyboardOptions
   )
}
  1. Dans la fonction TipTimeScreen(), mettez à jour le premier appel de fonction EditNumberField(), puis transmettez le paramètre nommé keyboardOptions pour le champ de texte Montant de la facture.
EditNumberField(
   label = R.string.bill_amount,
   keyboardOptions = KeyboardOptions(
       keyboardType = KeyboardType.Number,
       imeAction = ImeAction.Next
   ),
   value = amountInput,
   onValueChange = { amountInput = it }
)
  1. Dans le second appel de fonction EditNumberField(), remplacez la valeur imeAction du champ de texte Pourcentage de pourboire par ImeAction.Done. La fonction devrait se présenter comme suit :
EditNumberField(
   label = R.string.how_was_the_service,
   keyboardOptions = KeyboardOptions(
       keyboardType = KeyboardType.Number,
       imeAction = ImeAction.Done
   ),
   value = tipInput,
   onValueChange = { tipInput = it }
)
  1. Exécutez l'application. Les boutons Suivant et Terminé s'affichent, comme illustré sur les images suivantes :

  1. Saisissez le montant d'une facture, cliquez sur le bouton d'action Suivant, saisissez un pourcentage de pourboire, puis cliquez sur le bouton d'action Terminé. Rien ne se produit, car vous n'avez pas encore ajouté de fonctionnalité aux boutons. Pour ce faire, reportez-vous à la section suivante.

5. Définir les actions du clavier

Dans cette section, vous implémenterez la fonctionnalité permettant de déplacer le curseur vers le champ de texte suivant et de fermer le clavier pour améliorer l'expérience utilisateur avec la classe KeyboardActions. Cette classe permet aux développeurs de spécifier les actions déclenchées en réponse à l'action IME (éditeur de mode de saisie) des utilisateurs sur le clavier virtuel. Voici un exemple d'action IME : l'utilisateur clique sur le bouton d'action Suivant ou Terminé.

Voici ce que vous implémenterez :

  • Avec l'action Next (Suivant), déplacez le curseur dans le champ de texte suivant, qui correspond à la zone de texte Pourcentage de pourboire.
  • Avec l'action Done (Terminé), fermez le clavier virtuel.
  1. Dans la fonction EditNumberField(), ajoutez une variable val nommée focusManager et attribuez-lui la valeur LocalFocusManager.current.
val focusManager = LocalFocusManager.current

L'interface LocalFocusManager permet de contrôler le curseur dans Compose. Vous pouvez utiliser cette variable pour déplacer le curseur vers des zones de texte ou pour l'en supprimer.

  1. Importez import androidx.compose.ui.platform.LocalFocusManager.
  2. Dans la signature de la fonction EditNumberField(), ajoutez un autre paramètre keyboardActions de type KeyboardActions :
@Composable
fun EditNumberField(
   @StringRes label: Int,
   keyboardOptions: KeyboardOptions,
   keyboardActions: KeyboardActions,
   value: String,
   onValueChange: (String) -> Unit
) {
   //...
}
  1. Dans le corps de la fonction EditNumberField(), mettez à jour l'appel de la fonction TextField() et définissez le paramètre keyboardActions sur le paramètre transmis dans keyboardActions.
@Composable
fun EditNumberField(
   //...
) {
   TextField(
       //...
       keyboardActions = keyboardActions
   )
}

Vous pouvez désormais personnaliser les champs de texte avec différentes fonctionnalités pour chaque bouton d'action.

  1. Dans l'appel de fonction TipTimeScreen(), mettez à jour le premier appel de fonction EditNumberField() pour ajouter un paramètre nommé keyboardActions comme nouvel argument. Attribuez-lui une valeur, KeyboardActions( onNext = { } ) :
// Bill amount text field
EditNumberField(
   //...
   keyboardActions = KeyboardActions(
       onNext = { }
   ),
   //...
)

L'expression lambda du paramètre nommé onNext s'exécute lorsque l'utilisateur appuie sur le bouton d'action Suivant sur le clavier.

  1. Définissez l'expression lambda, demandez à FocusManager de déplacer le curseur vers le bas vers le composable suivant, à savoir Pourcentage de pourboire. Dans l'expression lambda, appelez la fonction moveFocus() au niveau de l'objet focusManager, puis transmettez l'argument FocusDirection.Down :
// Bill amount text field
EditNumberField(
   label = R.string.bill_amount,
   keyboardOptions = KeyboardOptions(
       keyboardType = KeyboardType.Number,
       imeAction = ImeAction.Next
   ),
   keyboardActions = KeyboardActions(
       onNext = { focusManager.moveFocus(FocusDirection.Down) }
   ),
   value = amountInput,
   onValueChange = { amountInput = it }
)

Dans ce cas, la fonction moveFocus() déplace le curseur dans la direction spécifiée, vers le bas dans le champ de texte Pourcentage de pourboire.

  1. Exécutez la commande d'importation suivante :
import androidx.compose.ui.focus.FocusDirection
  1. Ajoutez une implémentation similaire au champ de texte Pourcentage de pourboire. La différence consiste ici à définir un paramètre nommé onDone au lieu de onNext.
// Tip% text field
EditNumberField(
   //...
   keyboardActions = KeyboardActions(
       onDone = { }
   ),
   //...
)
  1. Une fois que l'utilisateur saisit le pourboire personnalisé, l'action "Terminé" du clavier devrait effacer le curseur, ce qui entraînera la fermeture du clavier. Définissez l'expression lambda, demandez à FocusManager de supprimer de curseur. Dans l'expression lambda, appelez la fonction clearFocus() au niveau de l'objet focusManager :
EditNumberField(
   label = R.string.how_was_the_service,
   keyboardOptions = KeyboardOptions(
       keyboardType = KeyboardType.Number,
       imeAction = ImeAction.Done
   ),
   keyboardActions = KeyboardActions(
       onDone = { focusManager.clearFocus() }),
   value = tipInput,
   onValueChange = { tipInput = it }
)

La fonction clearFocus() efface le curseur du composant dans lequel il se trouve.

  1. Exécutez l'application. Les actions du clavier font passer le curseur d'un composant à un autre, comme vous pouvez le voir sur cette image GIF :

3164e7a2f39a2d7b.gif

6. Ajouter un bouton bascule

Un bouton bascule permet d'activer ou de désactiver l'état d'un seul élément. Il implique deux états permettant à l'utilisateur de faire un choix entre deux options. Comme illustré dans les images suivantes, le bouton d'activation se compose d'un curseur à faire glisser sur une piste :

1. Curseur
2. Piste

Le bouton bascule est une commande de sélection qui vous permet d'indiquer un choix ou de déclarer une préférence, telles que des paramètres, comme illustré dans cette image :

a90c4e22e48b30e0.png

L'utilisateur peut soit faire glisser le curseur d'avant en arrière pour définir l'option de son choix, soit simplement appuyer sur le bouton pour l'activer. Vous trouverez un autre exemple d'activation et de désactivation dans l'image GIF ci-dessous, où le paramètre Options visuelles est basculé en mode sombre :

91b7bd7a6e02e5ff.gif

Pour en savoir plus, consultez la documentation sur les boutons bascules.

Vous pouvez utiliser le composable Switch pour que l'utilisateur ait la possibilité d'arrondir le pourboire au nombre entier le plus proche, comme illustré dans cette image :

cf89a61484296bab.png

Ajoutez une ligne pour les composables Text et Switch :

  1. Après la fonction EditNumberField(), ajoutez une fonction composable RoundTheTipRow(), puis transmettez un élément Modifier par défaut comme des arguments semblables à la fonction EditNumberField() :
@Composable
fun RoundTheTipRow(modifier: Modifier = Modifier) {
}
  1. Implémentez la fonction RoundTheTipRow(), ajoutez un composable Row de mise en page avec l'élément modifier suivant afin de définir la largeur maximale à l'écran pour les éléments enfants. Centrez l'alignement et assurez-vous que la taille correspond à 48 dp :
Row(
   modifier = Modifier
       .fillMaxWidth()
       .size(48.dp),
   verticalAlignment = Alignment.CenterVertically
) {
}
  1. Exécutez la commande d'importation suivante :
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Size
  1. Dans le bloc lambda du composable de mise en page Row, ajoutez un composable Text qui utilisera la ressource de chaîne R.string.round_up_tip pour afficher une chaîne Round up tip? :
Text(text = stringResource(R.string.round_up_tip))
  1. Après le composable Text, ajoutez un composable Switch, puis transmettez un paramètre nommé checked à roundUp et un paramètre onCheckedChange défini sur onRoundUpChanged.
Switch(
    checked = roundUp,
    onCheckedChange = onRoundUpChanged,
)

Ce tableau contient des informations sur ces paramètres, qui sont les mêmes que ceux que vous avez définis pour la fonction RoundTheTipRow() :

Paramètre

Description

checked

Indique si le bouton bascule est activé. Il s'agit de l'état du composable Switch.

onCheckedChange

Rappel à appeler en cas de clic sur le bouton bascule.

  1. Exécutez la commande d'importation suivante :
import androidx.compose.material.Switch
  1. Dans la fonction RoundTipRow(), ajoutez un paramètre roundUp de type Boolean et une fonction lambda onRoundUpChanged qui accepte une valeur Boolean et ne renvoie rien :
@Composable
fun RoundTheTipRow(
   roundUp: Boolean,
   onRoundUpChanged: (Boolean) -> Unit,
   modifier: Modifier = Modifier
)

Cette action hisse l'état du bouton bascule.

  1. Dans le composable Switch, ajoutez cet élément modifier pour aligner le composable Switch avec la fin de l'écran :
       Switch(
           modifier = modifier
               .fillMaxWidth()
               .wrapContentWidth(Alignment.End),
           //...
       )
  1. Exécutez la commande d'importation suivante :
import androidx.compose.foundation.layout.wrapContentWidth
  1. Dans la fonction TipTimeScreen(), ajoutez une variable var pour l'état du composable Switch. Créez une variable var nommée roundUp et définissez-la sur mutableStateOf(), en utilisant false comme argument par défaut. Délimitez l'appel avec remember { }.
fun TipTimeScreen() {
   //...
   var roundUp by remember { mutableStateOf(false) }

   //...
   Column(
       ...
   ) {
     //...
  }
}

Il s'agit de la variable d'état du composable Switch. "false" est l'état par défaut.

  1. Dans le bloc Column de la fonction TipTimeScreen() après le champ de texte Pourcentage de pourboire, appelez la fonction RoundTheTipRow() avec les arguments suivants : paramètre nommé roundUp défini sur roundUp et paramètre nommé onRoundUpChanged défini sur un rappel lambda qui met à jour la valeur roundUp :
@Composable
fun TipTimeScreen() {
   //...

   Column(
       ...
   ) {
       Text(
           ...
       )
       Spacer(...)
       EditNumberField(
           ...
       )
       EditNumberField(
           ...
       )
       RoundTheTipRow(roundUp = roundUp, onRoundUpChanged = { roundUp = it })
       Spacer(...)
       Text(
           ...
       )
   }
}

La ligne Arrondir le montant du pourboire s'affiche.

  1. Exécutez l'application. L'application affiche le bouton bascule Round up tip? (Arrondir le montant du pourboire ?), mais son curseur est à peine visible, comme vous pouvez le voir sur cette image :

Boutons bascules désélectionnés et sélectionnés avec des numéros identifiant les deux éléments et états1. Curseur
2. Piste

Au cours des prochaines étapes, vous améliorerez la visibilité du curseur en lui appliquant la couleur gris foncé.

  1. Dans le composable Switch() de la fonction RoundTheTipRow(), ajoutez un paramètre nommé colors.
  2. Définissez le paramètre nommé colors sur une fonction SwitchDefaults.colors() qui acceptera un paramètre nommé uncheckedThumbColor défini sur un argument Color.DarkGray.
Switch(
   //...
   colors = SwitchDefaults.colors(
       uncheckedThumbColor = Color.DarkGray
   )
)
  1. Exécutez la commande d'importation suivante :
import androidx.compose.material.SwitchDefaults
import androidx.compose.ui.graphics.Color

La fonction modulable RoundTheTipRow() devrait désormais ressembler à cet extrait de code :

@Composable
fun RoundTheTipRow(roundUp: Boolean, onRoundUpChanged: (Boolean) -> Unit) {
   Row(
       modifier = Modifier
           .fillMaxWidth()
           .size(48.dp),
       verticalAlignment = Alignment.CenterVertically
   ) {
       Text(stringResource(R.string.round_up_tip))
       Switch(
           modifier = Modifier
               .fillMaxWidth()
               .wrapContentWidth(Alignment.End),
           checked = roundUp,
           onCheckedChange = onRoundUpChanged,
           colors = SwitchDefaults.colors(
               uncheckedThumbColor = Color.DarkGray
           )
       )
   }
}
  1. Exécutez l'application. Comme vous pouvez le voir dans l'image suivante, la couleur de curseur du bouton bascule est différente :

24370de6d667a700.png

  1. Saisissez le montant de la facture et le pourcentage de pourboire, puis cliquez sur le bouton Round up tip? (Arrondir le pourboire ?). Le montant du pourboire n'est pas arrondi, car vous n'avez pas encore mis à jour la fonction calculateTip(), ce que vous ferez dans la section suivante.

Mettre à jour la fonction calculateTip() pour arrondir le pourboire

Modifiez la fonction calculateTip() pour qu'elle accepte une variable Boolean afin d'arrondir le pourboire à l'entier le plus proche :

  1. Pour arrondir le pourboire, la fonction calculateTip() doit connaître l'état du bouton bascule, qui correspond à une valeur Boolean. Dans la fonction calculateTip(), ajoutez un paramètre roundUp de type Boolean :
private fun calculateTip(
   amount: Double,
   tipPercent: Double = 15.0,
   roundUp: Boolean
): String {
   //...
}
  1. Dans la fonction calculateTip(), avant l'instruction return, ajoutez une condition if() qui vérifiera la valeur roundUp. Si la valeur de l'élément roundUp est true, définissez une variable tip et ajoutez kotlin.math.ceil(), puis transmettez la fonction tip comme argument :
if (roundUp)
   tip = kotlin.math.ceil(tip)

La fonction calculateTip() terminée devrait ressembler à cet extrait de code :

private fun calculateTip(amount: Double, tipPercent: Double = 15.0, roundUp: Boolean): String {
   var tip = tipPercent / 100 * amount
   if (roundUp)
       tip = kotlin.math.ceil(tip)
   return NumberFormat.getCurrencyInstance().format(tip)
}
  1. Dans la fonction TipTimeScreen(), mettez à jour l'appel de fonction calculateTip(), puis transmettez un paramètre roundUp :
val tip = calculateTip(amount, tipPercent, roundUp)
  1. Exécutez l'application. Comme vous pouvez le constater sur les images suivantes, le montant du pourboire est arrondi :

7. 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-tip-calculator.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 visualiser le code de solution, affichez-le sur GitHub.

8. Conclusion

Félicitations ! Vous avez ajouté une fonctionnalité de pourboire personnalisée à l'application Tip Time. Votre application permet maintenant aux utilisateurs de saisir un pourcentage de pourboire personnalisé et d'arrondir le montant du pourboire. Partagez le fruit de vos efforts sur les réseaux sociaux avec le hashtag #AndroidBasics.

En savoir plus