Navigation 3 היא ספריית ניווט שתוכננה מאפס ל-Jetpack Compose. במדריך הזה מוסבר איך מטמיעים את Navigation 3 באפליקציות ל-Wear OS.
מושגי ליבה
-
NavKey: מזהה ניתן לסריאליזציה (serializable) ובטוח לסוג (type-safe) של יעד (מסך) באפליקציה. -
NavBackStack: רשימה שניתנת לשינוי של מופעיNavKeyשמייצגים את היסטוריית הניווט. אפשר להוסיף פריטים לרשימה ולהוציא פריטים ממנה ישירות. rememberNavBackStack: קומפוזיציה שיוצרת ושומרת את מקבץ הפעילויות הקודמות (back stack) כשמתבצעים שינויים בהגדרות וכשתהליך מושבת.-
NavDisplay: רכיב הליבה של ממשק המשתמש שעוקב אחרי מקבץ פעילויות קודמות (back stack) ומציג את המסך הפעיל. -
EntryProvider: שפת תצורה (DSL) למיפוי שמקשרת ביןNavKeyלבין ממשק המשתמש בפועל של@Composable. -
SwipeDismissableSceneStrategy: אסטרטגיה ספציפית ל-Wear שעוטפת את המסכים בתנועת החלקה לסגירה ומטפלת באנימציות מובנות של חזרה.
שלב 1: מוסיפים יחסי תלות
מוסיפים לפרויקט את יחסי התלות הנדרשים: Navigation 3, Wear Compose ו-Serialization.
Groovy
dependencies { // Core Navigation 3 APIs implementation "androidx.navigation3:navigation3-runtime:1.2.0-alpha02" implementation "androidx.navigation3:navigation3-ui:1.2.0-alpha02" // Wear OS specific Navigation 3 integration implementation "androidx.wear.compose:compose-navigation3:1.6.1" // Kotlinx Serialization for type-safe routing implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.10.0" }
Kotlin
dependencies { // Core Navigation 3 APIs implementation("androidx.navigation3:navigation3-runtime:1.2.0-alpha02") implementation("androidx.navigation3:navigation3-ui:1.2.0-alpha02") // Wear OS specific Navigation 3 integration implementation("androidx.wear.compose:compose-navigation3:1.6.1") // Kotlinx Serialization for type-safe routing implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.10.0") }
שלב 2: הגדרת יעדים (NavKeys)
מסכים מוגדרים כאובייקטים או כסוגי נתונים סדרתיים עם הקלדה חזקה, שמטמיעים את הממשק NavKey.
@Serializable sealed interface Screen : NavKey { @Serializable data object Home : Screen @Serializable data class Details(val itemId: String) : Screen }
שלב 3: הגדרה של NavDisplay ומקבץ פעילויות קודמות (back stack)
בשורש של האפליקציה, מאתחלים את מקבץ הפעילויות הקודמות (back stack) ואת אסטרטגיית הסצנה של Wear OS, ואז מחברים אותם ל-NavDisplay.
// 1. Create the persistent back stack starting at the Home screen val backStack = rememberNavBackStack(Screen.Home) // 2. Initialize the Wear OS swipe-to-dismiss strategy val strategy = rememberSwipeDismissableSceneStrategy<NavKey>() // 3. Render the NavDisplay NavDisplay( backStack = backStack, sceneStrategies = listOf(strategy), entryProvider = entryProvider { // 4. Map keys to Composables entry<Screen.Home> { HomeScreen( onNavigateToDetails = { id -> backStack.add(Screen.Details(id)) } ) } entry<Screen.Details> { key -> DetailsScreen( itemId = key.itemId, onBack = { backStack.removeAt(backStack.lastIndex) } ) } } )
שלב 4: ביצוע פעולות ניווט
מכיוון שמקבץ הפעילויות הקודמות (back stack) הוא רק MutableList מותאם אישית, הניווט פשוט מאוד. אתם מבצעים פעולות ישירות במופע backStack:
- ניווט קדימה:
backStack.add(Screen.Details("123")) - הקודם:
backStack.removeLast()אוbackStack.removeLastOrNull() - ניקוי ואיפוס:
backStack.clear(); backStack.add(Screen.Home)(או שימוש בפעולות ברשימה כדי להחליף את המערך).
שלב 5: (אופציונלי) הגדרת היקף של ViewModels ליעדים
כברירת מחדל, ViewModels מוגדרים בהיקף של Activity. Navigation 3 מספק ארטיפקט ספציפי (lifecycle-viewmodel-navigation3) כדי להגדיר בבטחה את ההיקף של ViewModel ל-NavEntry במקבץ פעילויות קודמות (back stack). כשמוציאים את היעד ממקבץ פעילויות קודמות (back stack), ה-ViewModel מתנקה.
מוסיפים את התלות:
implementation("androidx.lifecycle:lifecycle-viewmodel-navigation3:...")מוסיפים את מעצב מאגר ה-ViewModel ל-
NavDisplayשלentryDecorators. כשמספקים מעצבים בהתאמה אישית כדי לשמור על מצב ComposerememberSaveable, צריך לכלול גם אתSaveableStateHolderNavEntryDecoratorבאופן מפורש:NavDisplay( backStack = backStack, sceneStrategies = listOf(strategy), entryDecorators = listOf( rememberSaveableStateHolderNavEntryDecorator(), rememberViewModelStoreNavEntryDecorator() ), entryProvider = entryProvider { entry<Screen.Home> { // Any viewModel() requested here will be scoped to this NavEntry val viewModel: HomeViewModel = viewModel() } } )