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

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

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

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

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

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

Kotlin


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

Groovy


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 על כל האזור שבו הפיגומים תופסים, בדרך כלל את החלון המלא. בנוסף, התשתית מצייר את ממשק המשתמש הספציפי של הניווט, כמו 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.windowWidthSizeClass == WindowWidthSizeClass.EXPANDED) {
        NavigationSuiteType.NavigationDrawer
    } else {
        NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(adaptiveInfo)
    }
}

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

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

יש לעיין בהנחיות לגבי Material Design:

אלה רכיבי הספרייה androidx.compose.material3: