Cómo modificar escenas con decoradores de escenas

Los decoradores de escenas te permiten modificar la escena que calcula la estrategia de escenas de tu app. En efecto, se usan para una segunda fase de construcción del contenido que muestra un elemento NavDisplay.

Este enfoque te permite encapsular funciones específicas, como mostrar componentes de la 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 de la app superior 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 persistente 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 escenas, implementa la interfaz SceneDecoratorStrategy. Esta interfaz tiene un método, decorateScene, que es análogo al calculateScene método de la SceneStrategy interfaz. decorateScene determina si puede decorar la escena:

  • Si tu estrategia de decorador de escenas no debe decorar la escena de entrada, muestra la escena de entrada tal como está.
  • Si debe decorar la escena de entrada, muestra una Scene nueva. En general, la escena que se muestra 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 decorador de escenas puede considerar 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
        }
    }

}

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 decora escenas, NavDisplay llama al método decorateScene de cada estrategia en sucesión 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 está decorando. Además, es probable que deba heredar (o modificar) los metadatos de la escena que está decorando, 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

    // ...
}

MyScene<T>(...) : Scene<T> by scene

Mantener 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 muestra después de la decoración de escenas puede seguir siendo la misma, incluso cuando cambia la clase de la escena que se muestra durante el cálculo de escenas. Cuando esto sucede y las escenas de decoración copian directamente la key de la escena que están decorando, 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 la 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

    // ...
}

sceneDecoratorStrategies