Los decoradores de escenas te permiten modificar la escena que calcula la estrategia de escena de tu app. En efecto, se usan para una segunda fase de construcción del contenido que muestra un NavDisplay.
Este enfoque te permite encapsular funciones específicas, como mostrar componentes comunes de la IU, en decoradores de escenas individuales.
Por ejemplo, considera una app de productividad que tiene tres rutas de nivel superior: una bandeja de entrada de correo electrónico, una bandeja de entrada de mensajes directos y una vista de calendario. Una app de este tipo podría usar dos decoradores de escenas: uno para agregar una barra superior de la app que muestre información y controles para la ruta de nivel superior actual, y otro para agregar una barra o un riel de navegación persistentes para navegar entre las rutas.
Crea una estrategia de decorador de escenas
Los decoradores de escenas siguen un patrón similar al de las estrategias de escenas. Para definir un decorador de escena, implementa la interfaz SceneDecoratorStrategy. Esta interfaz tiene un método, decorateScene, que es similar al método calculateScene de la interfaz SceneStrategy.
decorateScene determina si puede decorar la escena:
- Si tu estrategia de decorador de escenas no debería decorar la escena de entrada, devuelve la escena de entrada tal como está.
- Si debe decorar la escena de entrada, devuelve un
Scenenuevo. En general, la escena que se muestra toma la escena de entrada como parámetro y llama al métodocontentde la escena de entrada dentro de su propio métodocontent.
Para determinar si se debe decorar la escena de entrada y cómo hacerlo, tu estrategia de decorador de escenas puede considerar los metadatos de la Scene de entrada y las entradas contenidas en esa escena.
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 } } } data class MyDecoratingScene<T : Any>( val scene: Scene<T> ) : Scene<T> { // ... override val content = @Composable { scene.content() } }
Usa estrategias de decorador de escenas
Para usar estrategias de decorador de escenas, proporciónalas a tu NavDisplay con el parámetro sceneDecoratorStrategies. Cuando se decoran escenas, NavDisplay llama al método decorateScene de cada estrategia de forma sucesiva y pasa el resultado de cada llamada como entrada a la siguiente.
NavDisplay( // ... sceneDecoratorStrategies = listOf(firstSceneDecoratorStrategy, secondSceneDecoratorStrategy) )
Patrones comunes para los decoradores de escenas
Cuando implementes decoradores de escenas, ten en cuenta los siguientes patrones comunes:
Copiar propiedades
En muchos casos, la escena que se muestra cuando se decora una escena debe contener las mismas entradas y tener las mismas entradas anteriores que la escena que se decora. Además, es probable que deba heredar (o modificar) los metadatos de la escena que decora, en lugar de usar el comportamiento predeterminado. En el siguiente código, se muestra un ejemplo de cómo hacerlo:
data class CopyingScene<T : Any>( val scene: Scene<T> ) : Scene<T> { override val entries = scene.entries override val previousEntries = scene.previousEntries override val metadata = scene.metadata // ... }
Mantener las animaciones
Como se detalla en Cómo animar entre destinos, NavDisplay anima automáticamente las transiciones entre escenas cuando cambia una clave derivada de la clase de la escena actual y su propiedad key.
Cuando introduces decoradores de escenas en tu app, la clase de la escena que se devuelve después de la decoración de la escena puede permanecer igual, incluso cuando cambia la clase de la escena que se devuelve durante el cálculo de la escena. Cuando esto sucede y las escenas de decoración copian directamente la key de la escena que decoran, las animaciones integradas ya no se producen porque la clave derivada no cambia.
Para mantener la compatibilidad con la animación integrada, las escenas de decoración deben usar una clave derivada de la clase y el key de la escena que muestra calculateScene.
data class DerivedKeyScene<T : Any>( val scene: Scene<T> ) : Scene<T> { override val key = scene::class to scene.key // ... }