Przy tworzeniu grafu za pomocą lustrzanek DSL Kotlin przy zachowaniu miejsc docelowych zdarzenia nawigacji w jednym pliku mogą być trudne do zarządzania. To jest Zwłaszcza wtedy, gdy masz kilka niezależnych funkcji.
Wyodrębnij miejsca docelowe
Miejsca docelowe należy przenieść do rozszerzenia NavGraphBuilder
funkcji. Powinny mieszkać blisko tras, które je definiują.
wyświetlanych na nich ekranach. Przeanalizuj na przykład ten kod na poziomie aplikacji
który tworzy miejsce docelowe z listą kontaktów:
// MyApp.kt
@Serializable
object Contacts
@Composable
fun MyApp() {
...
NavHost(navController, startDestination = Contacts) {
composable<Contacts> { ContactsScreen( /* ... */ ) }
}
}
Kod związany z nawigacją należy przenieść do osobnego pliku:
// ContactsNavigation.kt
@Serializable
object Contacts
fun NavGraphBuilder.contactsDestination() {
composable<Contacts> { ContactsScreen( /* ... */ ) }
}
// MyApp.kt
@Composable
fun MyApp() {
...
NavHost(navController, startDestination = Contacts) {
contactsDestination()
}
}
Definicje tras i miejsc docelowych są teraz oddzielone od głównej aplikacji
możesz je aktualizować. Główna aplikacja zależy tylko od
. W tym przypadku jest to
NavGraphBuilder.contactsDestination()
Funkcja rozszerzenia NavGraphBuilder
tworzy pomost między bezstanowymi danymi
funkcji kompozycyjnej na poziomie ekranu i logiki charakterystycznej dla Nawigacji. Ta warstwa może
pozwalają też określić, skąd pochodzi dany stan
i jak obsługujesz zdarzenia.
Przykład
Fragment tego fragmentu zawiera nowe miejsce docelowe, w którym będą wyświetlane i aktualizuje istniejący adres docelowy listy kontaktów, aby udostępnił zdarzenie nawigacji, by wyświetlić szczegóły kontaktu.
Oto typowy zestaw ekranów, który może internal
wyświetlać się w osobnym module, więc
których inne moduły nie mają dostępu:
// 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) { ... }
Tworzenie miejsc docelowych
Ta funkcja rozszerzenia NavGraphBuilder
tworzy miejsce docelowe
który pokazuje funkcję ContactsScreen
kompozycyjną. Oprócz tego łączy
ekran z elementem ViewModel
, który przedstawia stan UI i obsługuje
logikę biznesową
związaną z ekranami.
Zdarzenia związane z nawigacją, np. nawigacja do miejsca docelowego szczegółów kontaktu,
są widoczne dla rozmówcy, a nie przez interfejs 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
)
}
}
W ten sam sposób możesz utworzyć miejsce docelowe z
ContactDetailsScreen
W tym przypadku zamiast pobierania stanu interfejsu użytkownika z
model wyświetlania można pobrać bezpośrednio z NavBackStackEntry
.
// ContactsNavigation.kt
@Serializable
internal data class ContactDetails(val id: String)
fun NavGraphBuilder.contactDetailsScreen() {
composable<ContactDetails> { navBackStackEntry ->
ContactDetailsScreen(contact = navBackStackEntry.toRoute())
}
}
Enkapuluj zdarzenia nawigacji
W ten sam sposób, w jaki zamykasz miejsca docelowe, możesz hermetyzować
zdarzeń nawigacji, aby uniknąć niepotrzebnego ujawniania typów tras. Zrób to do
tworzy funkcje rozszerzeń w klastrze NavController
.
// ContactsNavigation.kt
fun NavController.navigateToContactDetails(id: String) {
navigate(route = ContactDetails(id = id))
}
Połącz możliwości
Kod nawigacyjny do wyświetlania kontaktów jest teraz wyraźnie oddzielony od na wykresie nawigacji. Aplikacja musi:
- Wywołaj funkcje rozszerzenia
NavGraphBuilder
, aby utworzyć miejsca docelowe - Połącz te miejsca docelowe, wywołując funkcje rozszerzeń
NavController
dla zdarzeń nawigacji
// MyApp.kt
@Composable
fun MyApp() {
...
NavHost(navController, startDestination = Contacts) {
contactsDestination( contactId ->
navController.navigateToContactDetails(id = contactId)
})
contactDetailsDestination()
}
}
W skrócie
- Umieść kod nawigacyjny dla powiązanego zestawu ekranów, umieszczając go w oddzielnym pliku
- Aby udostępniać miejsca docelowe, utwórz w
NavGraphBuilder
funkcje rozszerzeń - Udostępnij zdarzenia nawigacji, tworząc funkcje rozszerzeń w:
NavController
- Aby zachować prywatność ekranów i rodzajów tras, użyj zasady
internal