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

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

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

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

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

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

Kotlin

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

מגניב

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

יצירת פיגום

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

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

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

שינוי הצבעים

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

הפרמטר containerColor מציין את צבע המשטח. ברירת המחדל היא צבע הרקע של ערכת הצבעים. הפרמטר contentColor מציין את צבע התוכן על אותו משטח. ברירת המחדל היא הצבע "on" של מה שצוין ב-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...
}

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