Cómo modificar escenas con decoradores de escenas

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 de IU comunes, 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 análogo al método calculateScene de la interfaz SceneStrategy. decorateScene determina si puede decorar la escena:

  • Si tu estrategia de decoración de escenas no debe decorar la escena de entrada, devuelve la escena de entrada tal como está.
  • Si debe decorar la escena de entrada, devuelve un nuevo Scene. En general, la escena que se devuelve toma la escena de entrada como parámetro y llama al método content de la escena de entrada dentro de su propio método content.

Para determinar si se debe decorar la escena de entrada y cómo hacerlo, tu estrategia de decoración de escenas puede tener en cuenta los metadatos de la Scene de entrada y las entradas que contiene 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
        }
    }

}

class MyDecoratingScene<T : Any>(scene: Scene<T>) : Scene<T> {

    // ...

    override val content = @Composable {
        scene.content()
    }
}

Usa estrategias de decoradores de escenas

Para usar estrategias de decoradores 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 elementos decorativos de escena, ten en cuenta los siguientes patrones comunes:

Copiar propiedades

En muchos casos, la escena que se devuelve después de decorar una escena debe contener las mismas entradas y tener las mismas entradas anteriores que la escena que se está decorando. Además, es probable que herede (o modifique) 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:

class CopyingScene<T : Any>(scene: Scene<T>) : Scene<T> {
    override val entries = scene.entries
    override val previousEntries = scene.previousEntries
    override val metadata = scene.metadata

    // ...
}

Cómo mantener las animaciones

Como se detalla en Cómo animar las transiciones 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 seguir siendo la misma, 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 el 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, la decoración de escenas debe usar una clave derivada de la clase y key de la escena que devuelve calculateScene.

class DerivedKeyScene<T : Any>(scene: Scene<T>) : Scene<T> {
    override val key = scene::class to scene.key

    // ...
}