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

シーン デコレータを使用すると、アプリのシーン戦略によって計算されたシーンを変更できます。実際には、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
        }
    }

}

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

    // ...

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

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

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

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

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

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

プロパティをコピーする

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

class CopyingScene<T : Any>(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 から派生したキーを使用する必要があります。

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

    // ...
}