Ao usar a DSL do Kotlin para construir seu gráfico, manter os destinos e eventos de navegação em um único arquivo pode ser difícil de manter. Isso é especialmente se você tiver vários atributos independentes.
Extrair destinos
Mova seus destinos para a extensão NavGraphBuilder
. Eles devem residir perto das rotas que os definem, e os
das telas que eles exibem. Por exemplo, considere o seguinte código no nível do app
que cria um destino que mostra uma lista de contatos:
// MyApp.kt
@Serializable
object Contacts
@Composable
fun MyApp() {
...
NavHost(navController, startDestination = Contacts) {
composable<Contacts> { ContactsScreen( /* ... */ ) }
}
}
Mova o código específico da navegação para um arquivo separado:
// ContactsNavigation.kt
@Serializable
object Contacts
fun NavGraphBuilder.contactsDestination() {
composable<Contacts> { ContactsScreen( /* ... */ ) }
}
// MyApp.kt
@Composable
fun MyApp() {
...
NavHost(navController, startDestination = Contacts) {
contactsDestination()
}
}
As definições de rotas e destinos agora estão separadas do app principal e
você pode atualizá-los de modo independente. O app principal depende apenas de um
função de extensão. Nesse caso,
NavGraphBuilder.contactsDestination()
:
A função de extensão NavGraphBuilder
forma a ponte entre um objeto sem estado
função combinável da tela e lógica específica de navegação. Essa camada pode
também definem de onde vem o estado e como você lida com eventos.
Exemplo
O snippet a seguir apresenta um novo destino para exibir a propriedade e atualiza o destino da lista de contatos existente para expor um evento de navegação para mostrar os detalhes do contato.
Este é um conjunto típico de telas que podem ser internal
no próprio módulo.
que outros módulos não possam acessá-los:
// 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) { ... }
Criar destinos
A seguinte função de extensão NavGraphBuilder
cria um destino
que mostra o elemento combinável ContactsScreen
. Além disso, ele agora conecta
na tela com uma ViewModel
que fornece o estado da interface da tela e processa as
lógica de negócios relacionada à tela.
Eventos de navegação, como navegar até o destino dos detalhes do contato,
expostos ao autor da chamada em vez de serem processados pelo 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
)
}
}
Você pode usar a mesma abordagem para criar um destino que exiba o
ContactDetailsScreen
: Nesse caso, em vez de obter o estado da interface de um
de visualização, você pode obtê-lo diretamente do NavBackStackEntry
.
// ContactsNavigation.kt
@Serializable
internal data class ContactDetails(val id: String)
fun NavGraphBuilder.contactDetailsScreen() {
composable<ContactDetails> { navBackStackEntry ->
ContactDetailsScreen(contact = navBackStackEntry.toRoute())
}
}
Encapsular eventos de navegação
Da mesma forma que você encapsula destinos,
eventos de navegação para evitar a exposição desnecessária de tipos de trajeto. Faça isso até
criando funções de extensão em NavController
;
// ContactsNavigation.kt
fun NavController.navigateToContactDetails(id: String) {
navigate(route = ContactDetails(id = id))
}
Reúna tudo
O código de navegação para exibir contatos agora está claramente separado dos gráfico de navegação do app. O app precisa:
- Chamar funções de extensão
NavGraphBuilder
para criar destinos - Conecte esses destinos chamando funções de extensão
NavController
. para eventos de navegação
// MyApp.kt
@Composable
fun MyApp() {
...
NavHost(navController, startDestination = Contacts) {
contactsDestination(onNavigateToContactDetails = { contactId ->
navController.navigateToContactDetails(id = contactId)
})
contactDetailsDestination()
}
}
Resumo
- Encapsule seu código de navegação para um conjunto de telas relacionadas colocando-o em um arquivo separado
- Expor destinos criando funções de extensão em
NavGraphBuilder
- Expor eventos de navegação criando funções de extensão no
NavController
- Use
internal
para manter a privacidade de telas e tipos de trajeto