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

בעזרת כלי עיצוב סצנות אפשר לשנות את הסצנה שמחושבת על ידי אסטרטגיית הסצנות של האפליקציה. למעשה, הם משמשים לשלב השני של בניית התוכן שמוצג על ידי NavDisplay.

הגישה הזו מאפשרת לכם להכניס פונקציונליות ספציפית, כמו הצגה של רכיבי ממשק משתמש נפוצים, לתוך מעצבי סצנות נפרדים.

לדוגמה, נניח שיש אפליקציה לפרודוקטיביות עם שלוש דרכים ברמה העליונה: תיבת דואר נכנס, תיבת דואר נכנס של צ'אט ישיר ותצוגת יומן. אפליקציה כזו יכולה להשתמש בשני רכיבי עיצוב של סצנות: אחד להוספת סרגל האפליקציה עליון שמציג מידע ופקדים עבור המסלול הנוכחי ברמה העליונה, ואחד להוספת סרגל ניווט או מסילת ניווט קבועים כדי לנווט בין המסלולים.

יצירת אסטרטגיה של מעצב סצנות

הדפוס של קישוטי סצנות דומה לזה של אסטרטגיות סצנות. כדי להגדיר דקורטור של סצנה, מטמיעים את הממשק SceneDecoratorStrategy. בממשק הזה יש method, ‏ decorateScene, שדומה ל-method‏ 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()
    }
}

שימוש בשיטות לקישוט סצנות

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

    // ...
}