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

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

    // ...
}

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

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

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

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

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

    // ...
}