Aplicar lógica ou wrappers aos destinos

É possível fornecer mais informações ou aplicar a mesma lógica a destinos usando a classe NavEntryDecorator. Essa classe encapsula cada NavEntry em um backstack com uma função combinável. Em outras palavras, ele decora o conteúdo da entrada.

Criar um decorator personalizado

Para criar um decorator, estenda a classe NavEntryDecorator e substitua os seguintes métodos:

  • decorate: uma lambda combinável chamada para cada NavEntry na backstack. Ele recebe o NavEntry como um parâmetro. Isso permite criar objetos de estado com chave para o contentKey da entrada. É possível usar CompositionLocalProvider para fornecer dependências ao conteúdo da entrada. Você também pode envolver o conteúdo com uma função combinável ou acionar efeitos colaterais. Sempre chame entry.Content() dentro desse método.
  • onPop: um callback invocado quando um NavEntry é removido da backstack e sai da composição. Ele recebe o contentKey da entrada removida. Use o contentKey para identificar e limpar qualquer estado associado a essa entrada.

O exemplo a seguir estende a classe NavEntryDecorator para criar um decorador personalizado.

// import androidx.navigation3.runtime.NavEntryDecorator
class CustomNavEntryDecorator<T : Any> : NavEntryDecorator<T>(
    decorate = { entry ->
        Log.d("CustomNavEntryDecorator", "entry with ${entry.contentKey} entered composition and was decorated")
        entry.Content()
    },
    onPop = { contentKey -> Log.d("CustomNavEntryDecorator", "entry with $contentKey was popped") }
)

Se o decorador precisar de acesso ao estado, crie uma função combinável que crie esse estado e use-o para construir o decorador. Para um exemplo de implementação, consulte o código-fonte de rememberSaveableStateHolderNavEntryDecorator. Isso cria o estado, um SaveableStateHolder, e o usa para construir o decorator.

Decorar uma pilha de retorno

Depois de criar o NavEntryDecorator, decore as entradas na pilha de retorno de uma destas duas maneiras:

  • Use rememberDecoratedNavEntries. Essa função é útil quando você tem várias pilhas de retorno, cada uma com seu próprio conjunto de decoradores. Consulte esta receita de código para mais detalhes. A função retorna uma lista decorada de NavEntrys que podem ser usadas com NavDisplay.
  • Forneça seu decorador diretamente para NavDisplay usando o parâmetro entryDecorators. O NavDisplay chama o rememberDecoratedNavEntries internamente e mostra as entradas decoradas.

Incluir o decorador padrão

A Navegação 3 inclui um decorador padrão chamado SaveableStateHolderNavEntryDecorator que permite que o estado de um NavEntry seja mantido em mudanças de configuração e encerramento do processo. Ele envolve o conteúdo NavEntry com um SaveableStateProvider, o que permite que as chamadas rememberSaveable dentro do conteúdo NavEntry funcionem corretamente.

A menos que seu decorador forneça um SaveableStateProvider, inclua SaveableStateHolderNavEntryDecorator como o primeiro decorador na lista de decoradores fornecidos. Ele é criado usando rememberSaveableStateHolderNavEntryDecorator.

Exemplo:

// import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator
NavDisplay(
    entryDecorators = listOf(
        rememberSaveableStateHolderNavEntryDecorator(),
        remember { CustomNavEntryDecorator() }
    ),
    // ...
)

Transmitir resultados usando ResultEventBusNavEntryDecorator

A partir do Navigation 3 1.2.0, você pode usar ResultEventBusNavEntryDecorator para fornecer um ResultEventBus a cada NavEntry usando o local de composição LocalResultEventBus.

Por padrão, o rememberResultEventBusNavEntryDecorator cria e lembra da própria instância de ResultEventBus internamente usando rememberResultEventBus. Se você precisar acessar o barramento de eventos fora da hierarquia de decoradores (como no scaffolding do app de nível superior), eleve o ResultEventBus chamando rememberResultEventBus e transmitindo-o para rememberResultEventBusNavEntryDecorator(resultEventBus):

val resultEventBus = rememberResultEventBus()

NavDisplay(
    /* ... */
    entryDecorators = listOf(
        rememberSaveableStateHolderNavEntryDecorator(),
        rememberResultEventBusNavEntryDecorator(resultEventBus = resultEventBus)
    )
)

Para mais detalhes sobre como enviar e observar resultados, consulte Retornar resultados.

Quando usar um decorator

Use um decorador para:

  • Crie uma dependência para cada NavEntry em um backstack. Por exemplo, o ViewModelStoreNavEntryDecorator cria um ViewModelStore para cada NavEntry.
  • Transmitir resultados e se comunicar entre destinos. Por exemplo, o ResultEventBusNavEntryDecorator fornece um ResultEventBus para destinos na backstack.
  • Escopo de um objeto para vários NavEntrys. Por exemplo, para compartilhar um ViewModel entre várias entradas.
  • Realize a mesma ação para vários NavEntrys. Por exemplo, para realizar operações de registro em log, depuração ou rastreamento para cada entrada.
  • Envolva os NavEntrys com a mesma função combinável.
  • Limpe o estado associado a NavEntrys. Por exemplo, quando uma entrada é removida da backstack, o ViewModelStoreNavEntryDecorator limpa o ViewModelStore associado.

Não use um decorador para:

  • Transmita uma dependência para um único NavEntry.
  • Forneça dependências com escopo mais amplo do que a backstack.

Em ambos os casos, transmita a dependência diretamente ao criar o NavEntry.

Para mais exemplos de código, consulte NavEntryDecorator.