使用场景装饰器修改场景

借助场景修饰器,您可以修改由应用场景 策略计算出的场景。实际上,它们用于构建 由 NavDisplay 显示的内容的第二阶段。

借助这种方法,您可以将特定功能(例如显示常见界面组件)封装到各个场景修饰器中。

例如,假设有一个效率类应用,其中包含三个顶级路由:电子邮件收件箱、即时消息收件箱和日历视图。此类应用可以使用两个场景修饰器,一个用于添加顶部应用栏,以显示当前顶级路由的信息和控件;另一个用于添加永久性导航栏或侧边栏,以便在路由之间导航。

创建场景修饰器策略

场景修饰器遵循与场景策略类似的模式。如需定义场景 修饰器,请实现 SceneDecoratorStrategy 接口。此接口 有一个方法 decorateScene,类似于 calculateScene 方法的 SceneStrategy 接口。 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

    // ...
}

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

维护动画

如在目的地之间添加动画过渡效果中所述,NavDisplay当从当前场景的类及其 key 属性派生的键发生更改时, 会自动为场景之间的过渡添加动画效果。

向应用引入场景修饰器时,即使在场景计算期间返回的场景的类发生更改,场景修饰后返回的场景的类也可以保持不变。发生这种情况时,直接复制要修饰的场景的 key 的修饰场景将不再发生内置动画,因为派生的键不会更改。

如需保持内置动画支持,修饰场景应使用从 calculateScene 返回的场景的类和 key 派生的键。

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

    // ...
}