使用場景修飾符修改場景

場景裝飾器可讓您修改應用程式場景策略計算的場景。實際上,這些方法用於建構 NavDisplay 顯示內容的第二階段。

這種做法可讓您將特定功能 (例如顯示常見的 UI 元件) 封裝到個別場景裝飾器中。

舉例來說,假設某個效率提升應用程式有三個頂層路徑:電子郵件收件匣、即時訊息收件匣和日曆檢視畫面。這類應用程式可以使用兩個場景裝飾器,一個用於新增頂端應用程式列,顯示目前頂層路徑的資訊和控制項,另一個用於新增永久導覽列或導覽欄,以便在路徑之間導覽。

建立場景裝飾器策略

場景裝飾器遵循與場景策略類似的模式。如要定義場景裝飾器,請實作 SceneDecoratorStrategy 介面。這個介面有一個方法 decorateScene,類似於 SceneStrategy 介面的 calculateScene 方法。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

    // ...
}

維持動畫

如「在目的地之間加上動畫效果」一文所述,當衍生自目前場景類別的索引鍵及其 key 屬性變更時,NavDisplay 會自動在場景之間加上動畫效果。

在應用程式中導入場景裝飾器時,即使場景計算期間傳回的場景類別有所變更,場景裝飾後傳回的場景類別仍可保持不變。發生這種情況時,如果裝飾場景直接複製所裝飾場景的 key,內建動畫就不會再發生,因為衍生索引鍵不會變更。

如要維持內建動畫支援,裝飾場景應使用衍生自類別的索引鍵,以及 calculateScene 傳回的場景 key。

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

    // ...
}