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 une cada NavEntry em uma backstack com uma função combinável. Em outras palavras, ele decora o conteúdo da entrada.

Criar um decorador personalizado

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

  • decorate: uma lambda combinável que é chamada para cada NavEntry na backstack. Ele recebe o NavEntry como parâmetro. Isso permite criar objetos de estado que são vinculados ao contentKey da entrada. É possível usar CompositionLocalProvider para fornecer dependências ao conteúdo da entrada. Também é possível cercar 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 ver um exemplo de implementação, consulte o código-fonte de rememberSaveableStateHolderNavEntryDecorator. Isso cria o estado, um SaveableStateHolder, e o usa para construir o decorador.

Decorar uma backstack

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

  • Use rememberDecoratedNavEntries. Essa função é útil quando você tem várias backstacks, cada uma com o 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 usados com NavDisplay.
  • Forneça o decorador diretamente para NavDisplay usando o parâmetro entryDecorators. O NavDisplay chama rememberDecoratedNavEntries em segundo plano e exibe as entradas decoradas.

Incluir o decorador padrão

O Navigation 3 inclui um decorador padrão chamado SaveableStateHolderNavEntryDecorator que permite que o estado de um NavEntry seja mantido durante mudanças de configuração e encerramento do processo. Ele envolve o conteúdo de NavEntry com um SaveableStateProvider, o que permite que as chamadas de rememberSaveable dentro do conteúdo de 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, é possível usar ResultEventBusNavEntryDecorator para fornecer um ResultEventBus a cada NavEntry usando o LocalResultEventBus local de composição.

Por padrão, o rememberResultEventBusNavEntryDecorator cria e armazena na memória a própria instância de ResultEventBus internamente usando rememberResultEventBus. Se você precisar acessar o barramento de eventos fora da hierarquia do decorador (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 decorador

Use um decorador para:

  • Crie uma dependência para cada NavEntry em uma 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.
  • Defina o 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 geração de registros, depuração ou rastreamento para cada entrada.
  • Envolva os NavEntrys com a mesma função combinável.
  • Limpar 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:

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

Nesses dois casos, transmita a dependência diretamente ao criar o NavEntry.

Para mais exemplos de código, consulte NavEntryDecorator.