הסבר על היסודות והטמעה שלהם

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

בניית מודל למצב הניווט

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

לחצן פעולה של מקלדת וירטואלית (סמל סימן וי) בתוך עיגול אדום.
איור 1. תרשים שבו מוצג איך סטאק החזרה משתנה בהתאם לאירועי הניווט של המשתמש.

יצירת סטאק אחורה

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

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

מושג מפתח ב-Navigation 3 API הוא שהסטאק של החזרה לאחור הוא בבעלותכם. הספרייה:

  • מצפה שהסטאק האחורי יהיה List<T> מגובה בתמונת מצב, כאשר T הוא הסוג של הסטאק האחורי keys. אפשר להשתמש ב-Any או לספק מפתחות משלכם עם סוג חזק יותר. כשאתם רואים את המונחים 'push' או 'pop', ההטמעה הבסיסית היא הוספה או הסרה של פריטים בסוף רשימה.
  • הוא עוקב אחרי סטאק החזרה ומשקף את המצב שלו בממשק המשתמש באמצעות NavDisplay.

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

// Define keys that will identify content
data object ProductList
data class ProductDetail(val id: String)

@Composable
fun MyApp() {

    // Create a back stack, specifying the key the app should start with
    val backStack = remember { mutableStateListOf<Any>(ProductList) }

    // Supply your back stack to a NavDisplay so it can reflect changes in the UI
    // ...more on this below...

    // Push a key onto the back stack (navigate forward), the navigation library will reflect the change in state
    backStack.add(ProductDetail(id = "ABC"))

    // Pop a key off the back stack (navigate back), the navigation library will reflect the change in state
    backStack.removeLastOrNull()
}

איך מקשרים מפתחות לתוכן

תוכן ב-Navigation 3 מתואר באמצעות NavEntry, שהיא כיתה שמכילה פונקציה שניתנת ליצירה. הוא מייצג יעד – קטע תוכן יחיד שהמשתמש יכול לנווט קדימה אליו וחזרה ממנו.

NavEntry יכול גם להכיל מטא-נתונים – מידע על התוכן. אובייקטים של מאגרים, כמו NavDisplay, יכולים לקרוא את המטא-נתונים האלה כדי להחליט איך להציג את התוכן של NavEntry. לדוגמה, אפשר להשתמש במטא-נתונים כדי לשנות את אנימציות ברירת המחדל של NavEntry ספציפי. NavEntry‏ metadata היא מפה של מפתחות String לערכים Any, שמספקת אחסון נתונים גמיש.

כדי להמיר key ל-NavEntry, יוצרים entryProvider. זוהי פונקציה שמקבלת key ומחזירה NavEntry עבור אותו key. בדרך כלל הוא מוגדר כפרמטר lambda כשיוצרים NavDisplay.

יש שתי דרכים ליצור entryProvider: ליצור פונקציית lambda ישירות או להשתמש ב-DSL של entryProvider.

יצירת פונקציית entryProvider ישירות

בדרך כלל יוצרים פונקציית entryProvider באמצעות משפט when, עם הסתעפות לכל אחד מהמפתחות.

entryProvider = { key ->
    when (key) {
        is ProductList -> NavEntry(key) { Text("Product List") }
        is ProductDetail -> NavEntry(
            key,
            metadata = mapOf("extraDataKey" to "extraDataValue")
        ) { Text("Product ${key.id} ") }

        else -> {
            NavEntry(Unit) { Text(text = "Invalid Key: $it") }
        }
    }
}

שימוש ב-entryProvider DSL

באמצעות ה-DSL של entryProvider תוכלו לפשט את פונקציית הלמהדה, כי לא תצטרכו לבדוק את כל סוגי המפתחות וליצור NavEntry לכל אחד מהם. לשם כך, משתמשים בפונקציית ה-builder entryProvider. הוא כולל גם התנהגות ברירת מחדל לחלופין (הצגת שגיאה) אם המפתח לא נמצא.

entryProvider = entryProvider {
    entry<ProductList> { Text("Product List") }
    entry<ProductDetail>(
        metadata = mapOf("extraDataKey" to "extraDataValue")
    ) { key -> Text("Product ${key.id} ") }
}

שימו לב לפרטים הבאים בקטע הקוד:

  • entry משמש להגדרת NavEntry עם הסוג והתוכן הניתנים ליצירה
  • entry מקבל פרמטר metadata כדי להגדיר את NavEntry.metadata

הצגת מחסנית הקודמים

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

  • סטאק הקוד הקודם – הוא צריך להיות מסוג SnapshotStateList<T>, כאשר T הוא הסוג של מפתחות סטאק הקוד הקודם. הוא List שניתן לצפות בו, כך שהוא מפעיל יצירת קומפוזיציה מחדש של NavDisplay כשהוא משתנה.
  • entryProvider להמרת המפתחות ב-back stack ל-NavEntry.
  • אפשר גם לספק פונקציית lambda לפרמטר onBack. הקריאה הזו מתבצעת כשהמשתמש מפעיל אירוע חזרה אחורה.

הדוגמה הבאה מראה איך יוצרים NavDisplay.

data object Home
data class Product(val id: String)

@Composable
fun NavExample() {

    val backStack = remember { mutableStateListOf<Any>(Home) }

    NavDisplay(
        backStack = backStack,
        onBack = { backStack.removeLastOrNull() },
        entryProvider = { key ->
            when (key) {
                is Home -> NavEntry(key) {
                    ContentGreen("Welcome to Nav3") {
                        Button(onClick = {
                            backStack.add(Product("123"))
                        }) {
                            Text("Click to navigate")
                        }
                    }
                }

                is Product -> NavEntry(key) {
                    ContentBlue("Product ${key.id} ")
                }

                else -> NavEntry(Unit) { Text("Unknown route") }
            }
        }
    )
}

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

התנהגות ברירת המחדל של NavDisplay עם שני יעדים.
איור 2. התנהגות ברירת המחדל של NavDisplay עם שני יעדים

סיכום של כל המידע

בתרשים הבא מוצגת זרימת הנתונים בין האובייקטים השונים בתפריט הניווט 3:

הדמיה חזותית של זרימת הנתונים בין האובייקטים השונים ב-Navigation 3.
איור 3. תרשים שבו מוצגת זרימת הנתונים דרך אובייקטים שונים ב-Navigation 3.
  1. אירועי ניווט מפעילים שינויים. מפתחות מתווספים או מוסרים מהמצב של סטאק החזרה אחורה בתגובה לאינטראקציות של משתמשים.

  2. שינוי במצב של סטאק העורפי מפעיל אחזור תוכן. ה-NavDisplay (רכיב מורכב שמרינדר מקבץ פעילויות קודמות) עוקב אחרי מקבץ הפעילויות הקודמות. בתצורת ברירת המחדל, הרשימה מציגה את הערך העליון ביותר ב-back stack בפריסה של חלונית אחת. כשהמפתח העליון ב-back stack משתנה, ה-NavDisplay משתמש במפתח הזה כדי לבקש את התוכן התואם מספק הרשומה.

  3. ספק הנתונים מספק תוכן. ספק הרשומה הוא פונקציה שממירה מפתח ל-NavEntry. כשספק הרשומה מקבל מפתח מה-NavDisplay, הוא מספק את ה-NavEntry המשויך, שמכיל גם את המפתח וגם את התוכן.

  4. התוכן מוצג. ה-NavDisplay מקבל את ה-NavEntry ומציג את התוכן.