Декораторы сцены позволяют изменять сцену, рассчитанную стратегией сцены вашего приложения. По сути, они используются на втором этапе создания контента, который показывается в 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() } }
Используйте стратегии декорирования сцены
Чтобы использовать стратегии декорирования сцены, передайте их в NavDisplay с помощью параметра sceneDecoratorStrategies. При оформлении сцен 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 декорируемой сцены, встроенные анимации больше не происходят, поскольку производный ключ не меняется.
Чтобы сохранить встроенную поддержку анимации, для декорирования сцен следует использовать ключ, полученный из класса и key сцены, возвращенной calculateScene.
data class DerivedKeyScene<T : Any>( val scene: Scene<T> ) : Scene<T> { override val key = scene::class to scene.key // ... }