Wenn Sie Ihre Grafik mit Kotlin DSL erstellen, Es kann schwierig sein, Navigationsereignisse in einer einzigen Datei zu verwalten. Dies ist Dies gilt insbesondere, wenn Sie mehrere unabhängige Funktionen haben.
Ziele extrahieren
Sie sollten Ihre Ziele in die Erweiterung NavGraphBuilder
verschieben
Funktionen. Sie sollten in der Nähe der Routen wohnen, auf denen sie definiert sind, und
Bildschirmen verwendet werden. Betrachten Sie zum Beispiel den folgenden Code auf App-Ebene
erstellt. Ein Ziel mit einer Liste von Kontakten wird erstellt:
// MyApp.kt
@Serializable
object Contacts
@Composable
fun MyApp() {
...
NavHost(navController, startDestination = Contacts) {
composable<Contacts> { ContactsScreen( /* ... */ ) }
}
}
Sie sollten den Navigations-spezifischen Code in eine separate Datei verschieben:
// ContactsNavigation.kt
@Serializable
object Contacts
fun NavGraphBuilder.contactsDestination() {
composable<Contacts> { ContactsScreen( /* ... */ ) }
}
// MyApp.kt
@Composable
fun MyApp() {
...
NavHost(navController, startDestination = Contacts) {
contactsDestination()
}
}
Die Routen- und Zieldefinitionen sind nun getrennt von der Haupt-App und
unabhängig voneinander aktualisieren. Die Haupt-App ist nur von einem
Erweiterungsfunktion. In diesem Fall ist das
NavGraphBuilder.contactsDestination()
Die Erweiterungsfunktion NavGraphBuilder
bildet die Brücke zwischen einem zustandslosen
zusammensetzbare Funktion auf Bildschirmebene
und navigationsspezifische Logik. Diese Ebene kann
und definieren, woher der Status stammt und wie Sie Ereignisse verarbeiten.
Beispiel
Mit dem folgenden Snippet wird ein neues Ziel zum Anzeigen der und aktualisiert das Ziel der bestehenden Kontaktliste, um Navigationsereignis, um die Details des Kontakts anzuzeigen.
Hier ist ein typischer Satz von Bildschirmen, die internal
in ein eigenes Modul gebracht werden können.
dass andere Module nicht darauf zugreifen können:
// 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) { ... }
Ziele erstellen
Mit der folgenden NavGraphBuilder
-Erweiterungsfunktion wird ein Ziel erstellt.
wo die zusammensetzbare Funktion ContactsScreen
angezeigt wird. Außerdem verbindet es jetzt
dem Bildschirm mit einem ViewModel
, der den Status der Bildschirm-UI angibt und
bildschirmbezogene Geschäftslogik.
Navigationsereignisse, z. B. das Navigieren zum Ziel der Kontaktdetails, sind
dem Aufrufer angezeigt und nicht vom ViewModel
verarbeitet.
// 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
)
}
}
Auf dieselbe Weise können Sie auch ein Ziel erstellen, das die
ContactDetailsScreen
In diesem Fall wird der UI-Status nicht von einem
erhalten Sie direkt im NavBackStackEntry
.
// ContactsNavigation.kt
@Serializable
internal data class ContactDetails(val id: String)
fun NavGraphBuilder.contactDetailsScreen() {
composable<ContactDetails> { navBackStackEntry ->
ContactDetailsScreen(contact = navBackStackEntry.toRoute())
}
}
Navigationsereignisse zusammenfassen
So wie Sie Ziele verkapseln, können Sie auch
Navigationsereignisse ein, um zu vermeiden, dass Routentypen unnötigerweise offengelegt werden. Vorgehensweise
Erweiterungsfunktionen werden für NavController
erstellt.
// ContactsNavigation.kt
fun NavController.navigateToContactDetails(id: String) {
navigate(route = ContactDetails(id = id))
}
Zusammenführung
Der Navigationscode für die Anzeige von Kontakten ist jetzt sauber vom im Navigationsdiagramm der App. Die App muss folgende Voraussetzungen erfüllen:
NavGraphBuilder
-Erweiterungsfunktionen aufrufen, um Ziele zu erstellen- Verbinden Sie diese Ziele, indem Sie
NavController
-Erweiterungsfunktionen aufrufen für Navigationsereignisse
// MyApp.kt
@Composable
fun MyApp() {
...
NavHost(navController, startDestination = Contacts) {
contactsDestination(onNavigateToContactDetails = { contactId ->
navController.navigateToContactDetails(id = contactId)
})
contactDetailsDestination()
}
}
Zusammenfassung
- Kapseln Sie Ihren Navigationscode für einen zusammengehörigen Satz von Bildschirmen, indem Sie ihn in einer separaten Datei
- Ziele durch Erstellen von Erweiterungsfunktionen in
NavGraphBuilder
freigeben - Navigationsereignisse durch Erstellen von Erweiterungsfunktionen für
NavController
freigeben - Mit
internal
können Sie Bildschirme und Routentypen privat halten