Lorsque vous utilisez le langage DSL Kotlin pour créer votre graphique, gardez les destinations et les événements de navigation dans un seul fichier peut être difficile à gérer. C'est surtout si vous avez plusieurs caractéristiques indépendantes.
Extraire les destinations
Vous devez déplacer vos destinations dans l'extension NavGraphBuilder
fonctions. Ils doivent se trouver à proximité des routes qui les définissent
des écrans qu'ils affichent. Prenons l'exemple du code suivant au niveau de l'application :
qui crée une destination qui affiche une liste de contacts:
// MyApp.kt
@Serializable
object Contacts
@Composable
fun MyApp() {
...
NavHost(navController, startDestination = Contacts) {
composable<Contacts> { ContactsScreen( /* ... */ ) }
}
}
Vous devez déplacer le code spécifique à la navigation dans un fichier distinct:
// ContactsNavigation.kt
@Serializable
object Contacts
fun NavGraphBuilder.contactsDestination() {
composable<Contacts> { ContactsScreen( /* ... */ ) }
}
// MyApp.kt
@Composable
fun MyApp() {
...
NavHost(navController, startDestination = Contacts) {
contactsDestination()
}
}
Les définitions des itinéraires et des destinations sont désormais distinctes de l'application principale.
vous pouvez les mettre à jour indépendamment. L'application principale ne dépend que d'un seul
fonction d'extension. Dans ce cas, il s’agit
NavGraphBuilder.contactsDestination()
La fonction d'extension NavGraphBuilder
constitue le pont entre un modèle sans état
Fonction composable au niveau de l'écran et logique spécifique à la navigation. Cette couche peut
définissent également d'où vient l'état
et comment vous gérez les événements.
Exemple
L'extrait de code suivant introduit une nouvelle destination pour afficher les coordonnées et met à jour la destination existante de la liste de contacts pour exposer événement de navigation pour afficher les détails du contact.
Voici un ensemble type d'écrans qui peuvent être internal
par rapport à leur propre module.
que les autres modules ne peuvent pas y accéder:
// ContactScreens.kt
// Displays a list of contacts
@Composable
internal fun ContactsScreen(
uiState: ContactsUiState,
onNavigateToContactDetails: (contactId: String) -> Unit
) { ... }
// Displays the details for an individual contact
@Composable
internal fun ContactDetailsScreen(contact: ContactDetails) { ... }
Créer des destinations
La fonction d'extension NavGraphBuilder
suivante crée une destination
qui affiche le composable ContactsScreen
. De plus, il connecte désormais
l'écran avec un ViewModel
qui fournit l'état de l'UI de l'écran et gère les
la logique métier liée à l'écran.
Les événements de navigation, comme l'accès à la destination des coordonnées, sont
exposées à l'appelant plutôt que gérées par ViewModel
.
// ContactsNavigation.kt
@Serializable
object Contacts
// Adds contacts destination to `this` NavGraphBuilder
fun NavGraphBuilder.contactsDestination(
// Navigation events are exposed to the caller to be handled at a higher level
onNavigateToContactDetails: (contactId: String) -> Unit
) {
composable<Contacts> {
// The ViewModel as a screen level state holder produces the screen
// UI state and handles business logic for the ConversationScreen
val viewModel: ContactsViewModel = hiltViewModel()
val uiState = viewModel.uiState.collectAsStateWithLifecycle()
ContactsScreen(
uiState,
onNavigateToContactDetails
)
}
}
Vous pouvez utiliser la même approche pour créer une destination qui affiche
ContactDetailsScreen
Dans ce cas, au lieu d'obtenir l'état de l'UI à partir d'un
vous pouvez l'obtenir directement à partir de NavBackStackEntry
.
// ContactsNavigation.kt
@Serializable
internal data class ContactDetails(val id: String)
fun NavGraphBuilder.contactDetailsScreen() {
composable<ContactDetails> { navBackStackEntry ->
ContactDetailsScreen(contact = navBackStackEntry.toRoute())
}
}
Encapsuler les événements de navigation
De la même manière que vous encapsulez des destinations, vous pouvez encapsuler
pour éviter d'exposer inutilement des types d'itinéraires. Pour ce faire, procédez comme suit :
en créant des fonctions d'extension sur NavController
.
// ContactsNavigation.kt
fun NavController.navigateToContactDetails(id: String) {
navigate(route = ContactDetails(id = id))
}
Réunissez
Le code de navigation permettant d'afficher les contacts est désormais clairement séparé du graphique de navigation de l'application. L'application doit:
- Appeler des fonctions d'extension
NavGraphBuilder
pour créer des destinations - Connecter ces destinations en appelant des fonctions d'extension
NavController
pour les événements de navigation
// MyApp.kt
@Composable
fun MyApp() {
...
NavHost(navController, startDestination = Contacts) {
contactsDestination(onNavigateToContactDetails = { contactId ->
navController.navigateToContactDetails(id = contactId)
})
contactDetailsDestination()
}
}
En résumé
- Encapsulez votre code de navigation pour un ensemble d'écrans associé en le plaçant dans un fichier distinct
- Exposez des destinations en créant des fonctions d'extension sur
NavGraphBuilder
- Exposer des événements de navigation en créant des fonctions d'extension sur
NavController
- Utiliser
internal
pour préserver la confidentialité des écrans et des types d'itinéraires