اصلاح صحنه‌ها با تزئین‌کننده‌های صحنه

تزیین‌کننده‌های صحنه به شما امکان می‌دهند صحنه محاسبه‌شده توسط راهبرد صحنه برنامه‌تان را اصلاح کنید. درواقع، از آن‌ها برای مرحله دوم ساختن محتوایی استفاده می‌شود که توسط 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

    // ...
}

حفظ پویانمایی‌ها

همان‌طور که در پویانمایی بین مقصدها به‌طور مفصل توضیح داده شده است، NavDisplay به‌طور خودکار گذار بین صحنه‌ها را وقتی کلید مشتق‌شده از کلاس صحنه فعلی و ویژگی key آن تغییر می‌کند پویانمایی می‌کند.

هنگام معرفی تزئین‌کننده‌های صحنه به برنامه‌تان، کلاس صحنه برگردانده‌شده پس‌از تزئین صحنه می‌تواند یکسان باقی بماند، حتی زمانی که کلاس صحنه برگردانده‌شده درطول محاسبه صحنه تغییر کند. وقتی این اتفاق می‌افتد و صحنه‌های تزئین مستقیماً key صحنه‌ای را که تزئین می‌کنند کپی می‌کنند، پویانمایی‌های داخلی دیگر اتفاق نمی‌افتند زیرا کلید مشتق‌شده تغییر نمی‌کند.

برای حفظ پشتیبانی از پویانمایی داخلی، صحنه‌های تزئینی باید از کلیدی استفاده کنند که از کلاس و key صحنه برگردانده‌شده توسط calculateScene مشتق شده باشد.

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

    // ...
}