A navegação descreve a forma como os usuários se movem pelo app. Eles interagem com elementos da interface, geralmente tocando ou clicando neles, e o app responde mostrando um novo conteúdo. Se o usuário quiser voltar ao conteúdo anterior, ele usa o gesto de volta ou toca no botão "Voltar".
Modelagem do estado de navegação
Uma maneira conveniente de modelar esse comportamento é com uma pilha de conteúdo. À medida que o usuário navega para frente até um novo conteúdo, ele é colocado no topo da pilha. Quando eles voltam desse conteúdo, ele é removido da pilha e o conteúdo anterior é exibido. Em termos de navegação, essa pilha geralmente é chamada de pilha de retorno porque representa o conteúdo a que o usuário pode voltar.
Criar uma pilha de retorno
Na navegação 3, a pilha de retorno não contém conteúdo. Em vez disso, ele contém referências a conteúdo, conhecidas como chaves. As chaves podem ser de qualquer tipo, mas geralmente são classes de dados simples e serializáveis. Usar referências em vez de conteúdo tem os seguintes benefícios:
- É simples navegar pressionando as chaves na backstack.
- Desde que as chaves sejam serializáveis, a pilha de retorno pode ser salva no armazenamento permanente, permitindo que ela sobreviva a mudanças de configuração e à morte do processo. Isso é importante porque os usuários esperam sair do app, voltar a ele depois e continuar de onde pararam com o mesmo conteúdo sendo mostrado. Consulte Salvar sua pilha de retorno para mais informações.
Um conceito importante da API Navigation 3 é que você é o proprietário da backstack. A biblioteca:
- Espera que sua pilha de retorno seja um
List<T>com estado de snapshot, em queTé o tipo dokeysda pilha de retorno. Você pode usarAnyou fornecer suas próprias chaves com tipagem mais forte. Quando você vê os termos "push" ou "pop", a implementação subjacente é adicionar ou remover itens do final de uma lista. - Observa a pilha de retorno e reflete o estado dela na interface usando um
NavDisplay.
O exemplo a seguir mostra como criar chaves e uma pilha de retorno e modificar a pilha de retorno em resposta a eventos de navegação do usuário:
// Define keys that will identify content data object ProductList data class ProductDetail(val id: String) @Composable fun MyApp() { // Create a back stack, specifying the key the app should start with val backStack = remember { mutableStateListOf<Any>(ProductList) } // Supply your back stack to a NavDisplay so it can reflect changes in the UI // ...more on this below... // Push a key onto the back stack (navigate forward), the navigation library will reflect the change in state backStack.add(ProductDetail(id = "ABC")) // Pop a key off the back stack (navigate back), the navigation library will reflect the change in state backStack.removeLastOrNull() }
Resolver chaves para conteúdo
O conteúdo é modelado no Navigation 3 usando NavEntry, que é uma classe
que contém uma função combinável. Ele representa um destino, ou seja, uma única parte
de conteúdo que o usuário pode navegar para frente e para trás.
Um NavEntry também pode conter metadados, que são informações sobre o conteúdo. Esses metadados podem ser lidos por objetos de contêiner, como NavDisplay, para ajudar a decidir como mostrar o conteúdo do NavEntry. Por exemplo, os metadados podem ser usados para substituir as animações padrão de um NavEntry específico. NavEntry
metadata é um mapa de chaves String para valores Any, oferecendo armazenamento de dados
versátil.
Para converter um key em um NavEntry, crie um provedor de entradas. Essa é uma
função que aceita um key e retorna um NavEntry para esse key. Normalmente, ele é definido como um parâmetro lambda ao criar um NavDisplay.
Há duas maneiras de criar um provedor de entradas: criando uma função lambda
diretamente ou usando a DSL entryProvider.
Criar uma função de provedor de entrada diretamente
Normalmente, você cria uma função de provedor de entradas usando uma instrução when, com uma ramificação para cada uma das suas chaves.
entryProvider = { key -> when (key) { is ProductList -> NavEntry(key) { Text("Product List") } is ProductDetail -> NavEntry( key, metadata = mapOf("extraDataKey" to "extraDataValue") ) { Text("Product ${key.id} ") } else -> { NavEntry(Unit) { Text(text = "Invalid Key: $it") } } } }
Usar a DSL entryProvider
A DSL entryProvider pode simplificar sua função lambda, evitando a necessidade de testar cada um dos tipos de chave e construir um NavEntry para cada um deles.
Use a função do builder entryProvider para isso. Ele também inclui o comportamento de
fallback padrão (gerando um erro) se a chave não for encontrada.
entryProvider = entryProvider { entry<ProductList> { Text("Product List") } entry<ProductDetail>( metadata = mapOf("extraDataKey" to "extraDataValue") ) { key -> Text("Product ${key.id} ") } }
Observe o seguinte no snippet:
entryé usado para definir umNavEntrycom o tipo e o conteúdo combinável especificados.entryaceita um parâmetrometadatapara definirNavEntry.metadata
Mostrar a pilha de retorno
A pilha de retorno representa o estado de navegação do app. Sempre que a pilha de retorno
mudar, a interface do app vai refletir o novo estado da pilha. Na Navegação 3, um
NavDisplay observa a backstack e atualiza a interface de acordo com ela. Construa
com os seguintes parâmetros:
- Sua pilha de retorno precisa ser do tipo
SnapshotStateList<T>, em queTé o tipo das chaves da pilha de retorno. É umListobservável para que ele aciona a recomposição deNavDisplayquando muda. - Um
entryProviderpara converter as chaves na sua pilha de retorno em objetosNavEntry. - Se quiser, forneça uma lambda ao parâmetro
onBack. Isso é chamado quando o usuário aciona um evento de retorno.
O exemplo a seguir mostra como criar um NavDisplay.
data object Home data class Product(val id: String) @Composable fun NavExample() { val backStack = remember { mutableStateListOf<Any>(Home) } NavDisplay( backStack = backStack, onBack = { backStack.removeLastOrNull() }, entryProvider = { key -> when (key) { is Home -> NavEntry(key) { ContentGreen("Welcome to Nav3") { Button(onClick = { backStack.add(Product("123")) }) { Text("Click to navigate") } } } is Product -> NavEntry(key) { ContentBlue("Product ${key.id} ") } else -> NavEntry(Unit) { Text("Unknown route") } } } ) }
Por padrão, o NavDisplay mostra o NavEntry mais alto na pilha de retorno em um layout de painel único. A gravação a seguir mostra o app em execução:
NavDisplay comportamento padrão com dois destinos.Para resumir
O diagrama a seguir mostra como os dados fluem entre os vários objetos na Navegação 3:
Os eventos de navegação iniciam mudanças. As chaves são adicionadas ou removidas da pilha de retorno em resposta às interações do usuário.
A mudança no estado da pilha de retorno aciona a recuperação de conteúdo. O
NavDisplay(um elemento combinável que renderiza uma backstack) observa a backstack. Na configuração padrão, ele mostra a entrada superior da pilha de retorno em um layout de painel único. Quando a chave principal na pilha de retorno muda, oNavDisplayusa essa chave para solicitar o conteúdo correspondente do provedor de entradas.O provedor de entradas fornece conteúdo. O provedor de entradas é uma função que resolve uma chave para um
NavEntry. Ao receber uma chave doNavDisplay, o provedor de entrada fornece oNavEntryassociado, que contém a chave e o conteúdo.O conteúdo é exibido. O
NavDisplayrecebe oNavEntrye mostra o conteúdo.