اصلاح صحنه‌ها با دکوراتورهای صحنه

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

}

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 صحنه‌ای را که تزئین می‌کنند کپی می‌کنند، انیمیشن‌های داخلی دیگر اتفاق نمی‌افتند زیرا کلید مشتق شده تغییر نمی‌کند.

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

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

    // ...
}