שינוי סצנות באמצעות מעצבי סצנות

בעזרת כלי לעיצוב סצנות אפשר לשנות את הסצנה שמחושבת על ידי אסטרטגיית הסצנה של האפליקציה. למעשה, הם משמשים לשלב השני של בניית התוכן שמוצג על ידי 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

    // ...
}