9. Gestion des états et des événements¶
Exemple : ExemplesEntrees¶
Exemple sur GitHub
Première version¶
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun FruitSelector(modifier: Modifier = Modifier) {
val fruits = listOf("Pomme", "Banane", "Orange", "Fraise", "Kiwi")
var expanded by remember { mutableStateOf(false) }
var selectedFruit by remember { mutableStateOf("") }
Column(modifier = modifier.padding(16.dp)) {
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = !expanded }
) {
TextField(
value = selectedFruit,
onValueChange = {},
readOnly = true,
label = { Text("Choisissez un fruit") },
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
modifier = Modifier
.menuAnchor()
.fillMaxWidth()
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false }
) {
fruits.forEach { fruit ->
DropdownMenuItem(
text = { Text(fruit) },
onClick = {
selectedFruit = fruit
expanded = false
}
)
}
}
}
Spacer(modifier = Modifier.height(16.dp))
if (selectedFruit.isNotEmpty()) {
Text("Fruit sélectionné : $selectedFruit")
}
}
}
@Composable
fun App(modifier: Modifier = Modifier) {
Column(modifier = modifier) {
TextLengthCounter()
Spacer(modifier = Modifier.height(100.dp))
FruitSelector()
}
}
Bien sûr, je vais vous donner une description générale de ces deux fonctions, en me concentrant particulièrement sur
FruitSelector.
Description générale¶
-
FruitSelector: C’est une fonction composable qui crée un sélecteur de fruits sous forme de menu déroulant. -
App: C’est la fonction composable principale qui structure l’interface utilisateur de l’application en combinant différents composants.
Focus sur FruitSelector¶
La fonction FruitSelector est un composant Jetpack Compose qui crée un menu déroulant permettant à l’utilisateur de
sélectionner un fruit parmi une liste prédéfinie. Voici ses principales caractéristiques :
-
Liste de fruits : Une liste statique de fruits est définie au début de la fonction.
-
États :
expanded: Un état booléen qui contrôle si le menu déroulant est ouvert ou fermé.selectedFruit: Un état qui stocke le fruit actuellement sélectionné.
-
Interface utilisateur :
- Utilise
ExposedDropdownMenuBoxpour créer le conteneur du menu déroulant. - Affiche un
TextFieldqui sert de déclencheur pour ouvrir le menu. Ce champ est en lecture seule et affiche le fruit sélectionné. - Le menu déroulant (
ExposedDropdownMenu) contient la liste des fruits, chacun représenté par unDropdownMenuItem.
- Utilise
-
Interaction :
- Lorsqu’un fruit est sélectionné, le menu se ferme et le fruit choisi est affiché dans le TextField.
- Un texte supplémentaire s’affiche en dessous pour confirmer le fruit sélectionné.
-
Mise en page :
- Utilise une
Columnpour organiser verticalement les éléments. - Ajoute des espacements et du rembourrage pour améliorer l’apparence.
- Utilise une
-
Personnalisation :
- Accepte un
modifieren paramètre pour permettre une personnalisation supplémentaire si nécessaire.
- Accepte un
Cette fonction démontre l’utilisation de plusieurs concepts importants de Jetpack Compose, tels que la gestion d’état, les composants d’interface utilisateur Material 3, et la création de composants interactifs. Elle offre une interface utilisateur intuitive pour la sélection d’éléments dans une liste, ce qui est une fonctionnalité courante dans de nombreuses applications.
Deuxième version¶
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun FruitSelector(
modifier: Modifier = Modifier,
fruits: List<String>,
selectedFruit: String,
onFruitSelected: (String) -> Unit = {}
) {
var expanded by remember { mutableStateOf(false) }
Column(modifier = modifier.padding(16.dp)) {
ExposedDropdownMenuBox(
expanded = expanded,
onExpandedChange = { expanded = !expanded }
) {
TextField(
value = selectedFruit,
onValueChange = {},
readOnly = true,
label = { Text("Choisissez un fruit") },
trailingIcon = {
ExposedDropdownMenuDefaults
.TrailingIcon(expanded = expanded)
},
modifier = Modifier
.menuAnchor()
.fillMaxWidth()
)
ExposedDropdownMenu(
expanded = expanded,
onDismissRequest = { expanded = false }
) {
fruits.forEach { fruit ->
DropdownMenuItem(
text = { Text(fruit) },
onClick = {
onFruitSelected(fruit)
expanded = false
}
)
}
}
}
Spacer(modifier = Modifier.height(16.dp))
if (selectedFruit.isNotEmpty()) {
Text("Fruit sélectionné : $selectedFruit")
}
}
}
@Composable
fun App(modifier: Modifier = Modifier) {
var selectedFruit1 by rememberSaveable { mutableStateOf("") }
var selectedFruit2 by rememberSaveable { mutableStateOf("") }
Column(modifier = modifier) {
TextLengthCounter()
Spacer(modifier = Modifier.height(100.dp))
FruitSelector(
fruits = listOf("Pomme", "Banane", "Orange", "Fraise", "Kiwi"),
selectedFruit = selectedFruit1,
onFruitSelected = { fruit -> selectedFruit1 = fruit }
)
Spacer(modifier = Modifier.height(10.dp))
FruitSelector(
fruits = listOf("Poire", "Mangue", "Orange", "Bleuet", "Pamplemousse"),
selectedFruit = selectedFruit2,
onFruitSelected = { fruit -> selectedFruit2 = fruit }
)
Spacer(modifier = Modifier.height(10.dp))
Text("Fruit sélectionné 1 : ${selectedFruit1 ?: "Aucun"}")
Text("Fruit sélectionné 2 : ${selectedFruit2 ?: "Aucun"}")
}
}
Cette nouvelle version de l’application démontre une refactorisation importante, principalement axée sur l’élévation de l’état (state hoisting) et la réutilisabilité des composants. Examinons en détail les changements et leurs implications :
Refactorisation de FruitSelector¶
-
Élévation de l’état :
selectedFruitn’est plus géré à l’intérieur deFruitSelector. Il est maintenant passé en tant que paramètre.- Une nouvelle fonction
onFruitSelectedest ajoutée comme paramètre pour gérer les changements de sélection.
-
Paramètres ajoutés :
fruits: List<String>: La liste des fruits est maintenant un paramètre, rendant le composant plus flexible.selectedFruit: String: L’état du fruit sélectionné est passé en paramètre.onFruitSelected: (String) -> Unit: Une fonction de rappel pour gérer la sélection d’un fruit.
-
État local restant :
expandedreste un état local car il concerne uniquement l’affichage du menu déroulant.
Modifications dans App¶
-
Gestion de l’état :
- Deux nouvelles variables d’état sont introduites :
selectedFruit1etselectedFruit2. - Ces états sont créés avec
rememberSaveablepour persister à travers les recompositions et les changements de configuration.
- Deux nouvelles variables d’état sont introduites :
-
Utilisation de FruitSelector :
- Deux instances de
FruitSelectorsont créées, chacune avec sa propre liste de fruits et son propre état. - L’état et la fonction de mise à jour sont passés à chaque
FruitSelector.
- Deux instances de
-
Affichage des sélections :
- Les fruits sélectionnés sont affichés en bas de l’App, démontrant que l’état est maintenant géré au niveau supérieur.
Avantages de cette refactorisation¶
-
Réutilisabilité :
FruitSelectorpeut maintenant être utilisé plusieurs fois avec différentes listes de fruits. -
Séparation des responsabilités : La gestion de l’état est séparée de l’affichage, rendant le code plus modulaire.
-
Contrôle accru : L’App a maintenant un contrôle total sur l’état des sélections, permettant des interactions plus complexes si nécessaire.
-
Testabilité améliorée : Il est plus facile de tester
FruitSelectorcar son comportement dépend entièrement des props passées. -
Flexibilité : La liste de fruits peut être dynamique, provenant par exemple d’une API ou d’une base de données.
Focus sur les variables d’état¶
-
Dans
App,selectedFruit1etselectedFruit2sont des variables d’état créées avecrememberSaveable. Cela signifie qu’elles conserveront leur valeur même lors des changements de configuration (comme la rotation de l’écran). -
Dans
FruitSelector, seulexpandedreste une variable d’état locale, car elle ne concerne que l’affichage interne du composant.
Cette refactorisation illustre des principes importants de Jetpack Compose, notamment l’élévation de l’état et la création de composants réutilisables et indépendants. Elle permet une meilleure gestion de l’état de l’application et une plus grande flexibilité dans la construction de l’interface utilisateur.