Modificare le scene con i decoratori di scene

I decoratori di scene ti consentono di modificare la scena calcolata dalla strategia delle scene della tua app. In effetti, vengono utilizzati per una seconda fase di costruzione dei contenuti visualizzati da un NavDisplay.

Questo approccio ti consente di incapsulare funzionalità specifiche, ad esempio la visualizzazione di componenti UI comuni, in singoli decoratori di scene.

Ad esempio, considera un'app per la produttività con tre route di primo livello: una casella di posta elettronica, una casella di posta per i messaggi diretti e una visualizzazione del calendario. Un'app di questo tipo potrebbe utilizzare due decoratori di scene, uno per aggiungere una barra delle app superiore che mostri informazioni e controlli per l'itinerario di primo livello corrente e un altro per aggiungere una barra di navigazione o una guida persistente per spostarsi tra gli itinerari.

Crea una strategia di decorazione delle scene

I decoratori di scene seguono un pattern simile a quello delle strategie di scene. Per definire un decoratore di scene, implementa l'interfaccia SceneDecoratorStrategy. Questa interfaccia ha un metodo, decorateScene, analogo al metodo calculateScene dell'interfaccia SceneStrategy. decorateScene determina se può decorare la scena:

  • Se la tua strategia di decorazione della scena non deve decorare la scena di input, restituisce la scena di input così com'è.
  • Se deve decorare la scena di input, restituisce un nuovo Scene. In generale, la scena restituita prende la scena di input come parametro e chiama il metodo content della scena di input all'interno del proprio metodo content.

Per determinare se e come decorare la scena di input, la strategia di decorazione delle scene può prendere in considerazione i metadati sia dell'Scene di input sia delle voci contenute in quella scena.

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()
    }
}

Utilizzare strategie di decorazione delle scene

Per utilizzare le strategie di decorazione della scena, fornisci queste informazioni a NavDisplay utilizzando il parametro sceneDecoratorStrategies. Quando decora le scene, NavDisplay chiama il metodo decorateScene di ogni strategia in successione, passando l'output di ogni chiamata come input alla successiva.

NavDisplay(
    // ...
    sceneDecoratorStrategies = listOf(firstSceneDecoratorStrategy, secondSceneDecoratorStrategy)
)

Pattern comuni per i decoratori di scene

Quando implementi i decoratori di scene, di seguito sono riportati alcuni pattern comuni da tenere presenti:

Copia proprietà

In molti casi, la scena restituita dalla decorazione di una scena deve contenere le stesse voci e avere le stesse voci precedenti della scena che sta decorando. Inoltre, è probabile che erediti (o modifichi) i metadati della scena che sta decorando, anziché utilizzare il comportamento predefinito. Il seguente codice mostra un esempio di come eseguire questa operazione:

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

    // ...
}

Mantenere le animazioni

Come descritto in Animare tra le destinazioni, NavDisplay anima automaticamente le transizioni tra le scene quando cambia una chiave derivata dalla classe della scena corrente e dalla relativa proprietà key.

Quando introduci i decoratori di scene nella tua app, la classe della scena restituita dopo la decorazione della scena può rimanere la stessa, anche quando la classe della scena restituita durante il calcolo della scena cambia. Quando ciò accade e le scene di decorazione copiano direttamente il key della scena che stanno decorando, le animazioni integrate non vengono più eseguite perché la chiave derivata non cambia.

Per mantenere il supporto integrato per l'animazione, le scene di decorazione devono utilizzare una chiave derivata dalla classe e key della scena restituita da calculateScene.

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

    // ...
}