Quando utilizzi la Kotlin DSL per costruire il tuo grafico, mantenendo le destinazioni e gli eventi di navigazione in un unico file possono essere difficili da gestire. Questo è soprattutto se hai più caratteristiche indipendenti.
Estrarre le destinazioni
Devi spostare le destinazioni nell'estensione NavGraphBuilder
funzioni. Devono trovarsi vicino alle route che li definiscono e
schermate visualizzate. Ad esempio, considera il seguente codice a livello di app
che crea una destinazione che mostra un elenco di contatti:
// MyApp.kt
@Serializable
object Contacts
@Composable
fun MyApp() {
...
NavHost(navController, startDestination = Contacts) {
composable<Contacts> { ContactsScreen( /* ... */ ) }
}
}
Dovresti spostare il codice specifico per la navigazione in un file separato:
// ContactsNavigation.kt
@Serializable
object Contacts
fun NavGraphBuilder.contactsDestination() {
composable<Contacts> { ContactsScreen( /* ... */ ) }
}
// MyApp.kt
@Composable
fun MyApp() {
...
NavHost(navController, startDestination = Contacts) {
contactsDestination()
}
}
I percorsi e le definizioni delle destinazioni sono ora separati dall'app principale e
puoi aggiornarli singolarmente. L'app principale dipende soltanto da una singola
di estensione. In questo caso,
NavGraphBuilder.contactsDestination()
.
La funzione di estensione NavGraphBuilder
costituisce il ponte tra una rete stateless
funzione componibile a livello di schermo e logica specifica per la navigazione. Questo livello può
definiscono anche la provenienza
dello stato e il modo in cui vengono gestiti gli eventi.
Esempio
Il seguente snippet introduce una nuova destinazione per visualizzare e aggiorna la destinazione esistente dell'elenco contatti per esporre un evento di navigazione per visualizzare i dettagli del contatto.
Di seguito è riportato un tipico set di schermate che possono essere internal
per il proprio modulo, quindi
che gli altri moduli non possono accedervi:
// 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) { ... }
Crea destinazioni
La seguente funzione di estensione NavGraphBuilder
crea una destinazione
che mostra il componibile ContactsScreen
. Inoltre, ora collega
schermata con un ViewModel
che fornisce lo stato UI della schermata e gestisce
della logica di business
relativa allo schermo.
Gli eventi di navigazione, come la navigazione verso la destinazione dei dati di contatto, vengono
esposto al chiamante anziché essere gestito da 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
)
}
}
Puoi usare lo stesso approccio per creare una destinazione che mostri i
ContactDetailsScreen
. In questo caso, invece di ottenere lo stato dell'interfaccia utente da un
di grandi dimensioni, puoi ottenerlo direttamente dal NavBackStackEntry
.
// ContactsNavigation.kt
@Serializable
internal data class ContactDetails(val id: String)
fun NavGraphBuilder.contactDetailsScreen() {
composable<ContactDetails> { navBackStackEntry ->
ContactDetailsScreen(contact = navBackStackEntry.toRoute())
}
}
Eventi di navigazione incapsulati
Analogamente a quanto accade per l'incapsulamento delle destinazioni,
eventi di navigazione per evitare di esporre inutilmente i tipi di percorso. Per farlo
creazione di funzioni di estensione su NavController
.
// ContactsNavigation.kt
fun NavController.navigateToContactDetails(id: String) {
navigate(route = ContactDetails(id = id))
}
Riunisci
Il codice di navigazione per visualizzare i contatti è ora ben separato dal grafico di navigazione dell'app. L'app deve:
- Chiama le funzioni dell'estensione
NavGraphBuilder
per creare destinazioni - Collega queste destinazioni chiamando le funzioni dell'estensione di
NavController
per eventi di navigazione
// MyApp.kt
@Composable
fun MyApp() {
...
NavHost(navController, startDestination = Contacts) {
contactsDestination(onNavigateToContactDetails = { contactId ->
navController.navigateToContactDetails(id = contactId)
})
contactDetailsDestination()
}
}
In sintesi
- Incapsula il codice di navigazione per un insieme di schermate correlato inserendolo in un file separato
- Esponi le destinazioni creando funzioni di estensione su
NavGraphBuilder
- Esponi gli eventi di navigazione creando funzioni di estensione su
NavController
- Usa
internal
per mantenere privati i tipi di schermate e route