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

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

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 מציין את הצבע של התוכן ב פלטפורמה הזו. ערך ברירת המחדל הוא הצבע 'מופעל' של מה שצוין עבור 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...
}

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