シーン デコレータでシーンを変更する

シーン デコレータを使用すると、アプリのシーン戦略によって計算されたシーンを変更できます。実際には、NavDisplay によって表示されるコンテンツを構築する第 2 段階で使用されます。

このアプローチでは、一般的な UI コンポーネントの表示などの特定の機能を個々のシーン デコレータにカプセル化できます。

たとえば、メールの受信トレイ、ダイレクト メッセージの受信トレイ、カレンダー ビューという 3 つのトップレベル ルートを持つ生産性向上アプリを考えてみましょう。このようなアプリでは、2 つのシーン デコレータを使用できます。1 つは、現在の最上位ルートの情報とコントロールを表示するトップ アプリバーを追加するためのもので、もう 1 つは、ルート間を移動するための永続的なナビゲーション バーまたはレールを追加するためのものです。

シーン デコレータ戦略を作成する

シーン デコレータは、シーン戦略と同様のパターンに従います。シーン デコレータを定義するには、SceneDecoratorStrategy インターフェースを実装します。このインターフェースには、SceneStrategy インターフェースの calculateScene メソッドに類似した decorateScene メソッドがあります。decorateScene は、シーンを装飾できるかどうかを決定します。

  • シーン デコレータ戦略が入力シーンを装飾しない場合は、入力シーンをそのまま返します。
  • 入力シーンを装飾する必要がある場合は、新しい Scene を返します。一般に、返されるシーンは入力シーンをパラメータとして受け取り、独自の content メソッド内で入力シーンの content メソッドを呼び出します。

入力シーンを装飾するかどうか、またどのように装飾するかを決定するために、シーン デコレータ戦略では、入力 Scene とそのシーンに含まれるエントリの両方のメタデータを考慮できます。

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

シーン デコレータ戦略を使用する

シーン デコレータ戦略を使用するには、sceneDecoratorStrategies パラメータを使用して NavDisplay に指定します。シーンを装飾する際、NavDisplay は各戦略の decorateScene メソッドを連続して呼び出し、各呼び出しの出力を次の呼び出しの入力として渡します。

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

シーン デコレータの一般的なパターン

シーン デコレータを実装する際は、次の一般的なパターンに注意してください。

プロパティをコピー

多くの場合、シーンを装飾して返されるシーンには、装飾するシーンと同じエントリが含まれ、同じ前のエントリが含まれている必要があります。また、デフォルトの動作を使用するのではなく、装飾するシーンのメタデータを継承(または変更)する必要があります。次のコードは、この方法の例を示しています。

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

    // ...
}

アニメーションを維持する

デスティネーション間のアニメーションで詳しく説明されているように、NavDisplay は、現在のシーンのクラスとその key プロパティから派生したキーが変更されると、シーン間の遷移を自動的にアニメーション化します。

アプリにシーン デコレータを導入すると、シーン計算中に返されるシーンのクラスが変更された場合でも、シーン デコレーション後に返されるシーンのクラスは同じままになります。この場合、デコレーション シーンがデコレーション対象のシーンの key を直接コピーすると、派生キーが変更されないため、組み込みアニメーションは発生しなくなります。

組み込みのアニメーション サポートを維持するには、デコレーション シーンで、calculateScene によって返されるシーンのクラスと key から派生したキーを使用する必要があります。

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

    // ...
}