Com os decoradores de cena, é possível modificar a cena calculada pela estratégia de cena do app. Na prática, eles são usados para uma segunda fase de construção do
conteúdo exibido por um NavDisplay.
Essa abordagem permite encapsular funcionalidades específicas, como mostrar componentes de interface comuns, em decoradores de cena individuais.
Por exemplo, considere um app de produtividade com três rotas de nível superior: uma caixa de entrada de e-mail, uma caixa de entrada de mensagens diretas e uma visualização de calendário. Um app desse tipo pode usar dois decoradores de cena, um para adicionar uma barra superior de apps que mostre informações e controles para a rota de nível superior atual e outro para adicionar uma barra de navegação ou coluna persistente para navegar entre as rotas.
Criar uma estratégia de decorador de cena
Os decoradores de cena seguem um padrão semelhante ao das estratégias de cena. Para definir um decorator de cena, implemente a interface SceneDecoratorStrategy. Essa interface tem um método, decorateScene, que é análogo ao método calculateScene da interface SceneStrategy.
decorateScene determina se é possível decorar a cena:
- Se a estratégia de decorador de cena não decorar a cena de entrada, ela vai retornar a cena de entrada como está.
- Se precisar decorar a cena de entrada, ele vai retornar um novo
Scene. Em geral, a cena retornada usa a cena de entrada como um parâmetro e chama o métodocontentda cena de entrada no próprio métodocontent.
Para determinar se e como a cena de entrada deve ser decorada, sua estratégia de
decorador de cena pode considerar os metadados da Scene de entrada e
das entradas contidas nessa cena.
class MySceneDecoratorStrategy<T : Any> : SceneDecoratorStrategy<T> { override fun SceneDecoratorStrategyScope<T>.decorateScene(scene: Scene<T>): Scene<T> { // `shouldDecorate` determines if the scene should be decorated based on scene.metadata, // scene.entries.metadata, or any other relevant state. return if (shouldDecorate(scene)) { MyDecoratingScene(scene) } else { scene } } } class MyDecoratingScene<T : Any>(scene: Scene<T>) : Scene<T> { // ... override val content = @Composable { scene.content() } }
Usar estratégias de decorador de cena
Para usar estratégias de decorador de cena, forneça-as ao NavDisplay usando o
parâmetro sceneDecoratorStrategies. Ao decorar cenas, NavDisplay chama
o método decorateScene de cada estratégia em sucessão, transmitindo a saída de
cada chamada como a entrada para a próxima.
NavDisplay( // ... sceneDecoratorStrategies = listOf(firstSceneDecoratorStrategy, secondSceneDecoratorStrategy) )
Padrões comuns para decoradores de cena
Ao implementar decoradores de cena, estes são alguns padrões comuns que precisam ser considerados:
Copiar propriedades
Em muitos casos, a cena retornada ao decorar uma cena precisa conter as mesmas entradas e ter as mesmas entradas anteriores da cena que está sendo decorada. Além disso, é provável que ele herde (ou modifique) os metadados da cena que está decorando, em vez de usar o comportamento padrão. O código a seguir demonstra um exemplo de como fazer isso:
class CopyingScene<T : Any>(scene: Scene<T>) : Scene<T> { override val entries = scene.entries override val previousEntries = scene.previousEntries override val metadata = scene.metadata // ... }
Manter animações
Conforme detalhado em Animar entre destinos, o NavDisplay anima automaticamente as transições entre cenas quando uma chave derivada da classe da cena atual e da propriedade key muda.
Ao introduzir decoradores de cena no app, a classe da cena retornada
após a decoração pode permanecer a mesma, mesmo quando a classe da cena
retornada durante o cálculo de cena muda. Quando isso acontece e
as cenas de decoração copiam diretamente o key da cena que estão decorando, as
animações integradas não acontecem mais porque a chave derivada não muda.
Para manter o suporte à animação integrada, as cenas de decoração precisam usar uma chave
derivada da classe e do key da cena retornada por calculateScene.
class DerivedKeyScene<T : Any>(scene: Scene<T>) : Scene<T> { override val key = scene::class to scene.key // ... }