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

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

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

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...
}

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