פיתוח ניווט דינמי

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

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

  • סרגל הניווט אם הרוחב או הגובה קומפקטיים או אם המכשיר נמצא במצב שולחני
  • פס ניווט לכל שאר הפעולות
איור 1. NavigationSuiteScaffold מציג סרגל ניווט בחלונות קומפקטיים.
איור 2. NavigationSuiteScaffold מציג פס ניווט בחלונות מורחבים.

הוספת יחסי תלות

NavigationSuiteScaffold הוא חלק מהספרייה Material3 adaptive navigation suite. מוסיפים תלות בספרייה בקובץ build.gradle של האפליקציה או המודול:

Kotlin

implementation("androidx.compose.material3:material3-adaptive-navigation-suite")

Groovy

implementation 'androidx.compose.material3:material3-adaptive-navigation-suite'

יצירת פיגום

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

enum class AppDestinations(
    @StringRes val label: Int,
    val icon: ImageVector,
    @StringRes val contentDescription: Int
) {
    HOME(R.string.home, Icons.Default.Home, R.string.home),
    FAVORITES(R.string.favorites, Icons.Default.Favorite, R.string.favorites),
    SHOPPING(R.string.shopping, Icons.Default.ShoppingCart, R.string.shopping),
    PROFILE(R.string.profile, Icons.Default.AccountBox, R.string.profile),
}

כדי להשתמש ב-NavigationSuiteScaffold, צריך לעקוב אחרי היעד הנוכחי. אפשר לעשות את זה באמצעות rememberSaveable:

var currentDestination by rememberSaveable { mutableStateOf(AppDestinations.HOME) }

בדוגמה הבאה, הפרמטר navigationSuiteItems (סוג NavigationSuiteScope) משתמש בפונקציה item כדי להגדיר את ממשק המשתמש של הניווט ליעד מסוים. ממשק המשתמש של היעד משמש בסרגלי ניווט, בחלוניות צדדיות ובמגירות. כדי ליצור פריטי ניווט, צריך להשתמש בלולאה על AppDestinations (מוגדר בקטע הקוד הקודם):

NavigationSuiteScaffold(
    navigationSuiteItems = {
        AppDestinations.entries.forEach {
            item(
                icon = {
                    Icon(
                        it.icon,
                        contentDescription = stringResource(it.contentDescription)
                    )
                },
                label = { Text(stringResource(it.label)) },
                selected = it == currentDestination,
                onClick = { currentDestination = it }
            )
        }
    }
) {
    // TODO: Destination content.
}

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

NavigationSuiteScaffold(
    navigationSuiteItems = { /*...*/ }
) {
    // Destination content.
    when (currentDestination) {
        AppDestinations.HOME -> HomeDestination()
        AppDestinations.FAVORITES -> FavoritesDestination()
        AppDestinations.SHOPPING -> ShoppingDestination()
        AppDestinations.PROFILE -> ProfileDestination()
    }
}

שינוי הצבעים

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

הפרמטר containerColor מציין את צבע המשטח. ברירת המחדל היא צבע הרקע של ערכת הצבעים. הפרמטר contentColor מציין את צבע התוכן ב אותו משטח. ברירת המחדל היא הצבע 'מופעל' של מה שמוגדר ב-containerColor. לדוגמה, אם containerColor משתמש בצבע background, אז contentColor משתמש בצבע onBackground. מידע נוסף על אופן הפעולה של מערכת הצבעים זמין במאמר בנושא עיצוב ערכות נושא ב-Compose ב-Material Design 3. כשמבטלים את ברירת המחדל של הערכים האלה, צריך להשתמש בערכים שמוגדרים בעיצוב כדי שהאפליקציה תתמוך במצבי תצוגה כהה ובהירה:

NavigationSuiteScaffold(
    navigationSuiteItems = { /* ... */ },
    containerColor = MaterialTheme.colorScheme.primary,
    contentColor = MaterialTheme.colorScheme.onPrimary,
) {
    // Content...
}

ממשק המשתמש של הניווט מצויר מעל פני השטח של NavigationSuiteScaffold. ערכי ברירת המחדל של צבעי ממשק המשתמש מסופקים על ידי NavigationSuiteDefaults.colors(), אבל אפשר גם לשנות את הערכים האלה. לדוגמה, אם רוצים שרק הרקע של סרגל הניווט יהיה שקוף וששאר הערכים יהיו ברירת המחדל, צריך לשנות את navigationBarContainerColor:

NavigationSuiteScaffold(
    navigationSuiteItems = { /* ... */ },
    navigationSuiteColors = NavigationSuiteDefaults.colors(
        navigationBarContainerColor = Color.Transparent,
    )
) {
    // Content...
}

בסופו של דבר, אתם יכולים להתאים אישית כל פריט בממשק המשתמש של הניווט. כשקוראים לפונקציה item, אפשר להעביר מופע של NavigationSuiteItemColors. הכיתה מציינת את הצבעים של הפריטים בסרגל הניווט, במגירת הניווט ובניווט. כלומר, אתם יכולים להשתמש באותם צבעים בכל סוגי ממשקי המשתמש של הניווט, או לשנות את הצבעים לפי הצורך. מגדירים את הצבעים ברמה NavigationSuiteScaffold כדי להשתמש באותו מופע אובייקט לכל הפריטים, וקוראים לפונקציה NavigationSuiteDefaults.itemColors() כדי לשנות רק את הצבעים שרוצים לשנות:

val myNavigationSuiteItemColors = NavigationSuiteDefaults.itemColors(
    navigationBarItemColors = NavigationBarItemDefaults.colors(
        indicatorColor = MaterialTheme.colorScheme.primaryContainer,
        selectedIconColor = MaterialTheme.colorScheme.onPrimaryContainer
    ),
)

NavigationSuiteScaffold(
    navigationSuiteItems = {
        AppDestinations.entries.forEach {
            item(
                icon = {
                    Icon(
                        it.icon,
                        contentDescription = stringResource(it.contentDescription)
                    )
                },
                label = { Text(stringResource(it.label)) },
                selected = it == currentDestination,
                onClick = { currentDestination = it },
                colors = myNavigationSuiteItemColors,
            )
        }
    },
) {
    // Content...
}

התאמה אישית של סוגי הניווט

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

val adaptiveInfo = currentWindowAdaptiveInfo()
val customNavSuiteType = with(adaptiveInfo) {
    if (windowSizeClass.isWidthAtLeastBreakpoint(WIDTH_DP_EXPANDED_LOWER_BOUND)) {
        NavigationSuiteType.NavigationDrawer
    } else {
        NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(adaptiveInfo)
    }
}

NavigationSuiteScaffold(
    navigationSuiteItems = { /* ... */ },
    layoutType = customNavSuiteType,
) {
    // Content...
}

מקורות מידע נוספים