רכיב הניווט מספק שפה ספציפית לדומיין מבוססת-Kotlin, או
DSL, המסתמכת על מודל בטוח מסוג Kotlin
Builders
הקצר הזה. התשובות שלך יעזרו לנו להשתפר. ה-API הזה מאפשר לכתוב את התרשים באופן הצהרתי בקוד Kotlin
מאשר בתוך משאב XML. היא יכולה להיות שימושית אם רוצים ליצור
ניווט דינמי. לדוגמה, האפליקציה יכולה להוריד ולשמור במטמון
להגדרת ניווט משירות אינטרנט חיצוני, ואז להשתמש בו
כדי ליצור באופן דינמי תרשים ניווט
onCreate()
.
יחסי תלות
כדי להשתמש ב-Kotlin DSL עם Fragments, יש להוסיף את התלות הבאה
קובץ build.gradle
:
Groovy
dependencies { def nav_version = "2.8.4" api "androidx.navigation:navigation-fragment-ktx:$nav_version" }
Kotlin
dependencies { val nav_version = "2.8.4" api("androidx.navigation:navigation-fragment-ktx:$nav_version") }
יצירת תרשים
הנה דוגמה בסיסית שמבוססת על החמנייה
app. בשביל זה
לדוגמה, יש לנו שני יעדים: home
ו-plant_detail
. home
היעד מוצג כשהמשתמש מפעיל את האפליקציה בפעם הראשונה. היעד הזה
מציג רשימה של צמחים מהגינה של המשתמש. כשהמשתמש בוחר באחת מהאפשרויות הבאות:
הצמחים, האפליקציה מנווטת ליעד plant_detail
.
איור 1 מציג את היעדים האלה יחד עם הארגומנטים הנדרשים
יעד אחד (plant_detail
) ופעולה, to_plant_detail
, שהאפליקציה משתמשת בהם
כדי לנווט מhome
אל plant_detail
.
אירוח תרשים Nav של Kotlin DSL
לפני שיוצרים את תרשים הניווט של האפליקציה, צריך מקום שבו
גרפי. הדוגמה הזו משתמשת במקטעים, ולכן היא מארחת את התרשים
NavHostFragment
בתוך
FragmentContainerView
:
<!-- activity_garden.xml -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true" />
</FrameLayout>
שימו לב שהמאפיין app:navGraph
לא מוגדר בדוגמה הזו. התרשים
לא מוגדר כמשאב ב-
התיקייה res/navigation
, כך שצריך להגדיר אותה כחלק מonCreate()
במהלך הפעילות.
ב-XML, פעולה קושרת מזהה יעד עם ארגומנט אחד או יותר. עם זאת, בעת שימוש ב-DSL של ניווט, נתיב יכול להכיל ארגומנטים כחלק את המסלול. המשמעות היא שאין קונספט של פעולות כשמשתמשים ב-DSL.
השלב הבא הוא להגדיר את הנתיבים שבהם תשתמשו בזמן הגדרת גרפי.
יצירת מסלולים לתרשים
תרשימי ניווט מבוססי XML מנותחים כחלק
בתהליך ה-build של Android. נוצר קבוע מספרי לכל id
המוגדר בגרף. המזהים הסטטיים שנוצרו בזמן build לא
זמין בעת יצירת תרשים הניווט בזמן הריצה, כדי שה-DSL לניווט
משתמש באפשרויות סידוריות
סוגים במקום
המזהים. כל נתיב מיוצג על ידי סוג ייחודי.
כשמדובר בארגומנטים, הם מובנים במסלול . כך אפשר לשמור על בטיחות ארגומנטים של ניווט.
@Serializable data object Home
@Serializable data class Plant(val id: String)
יצירת תרשים באמצעות Nav GraphBuilder DSL
אחרי שמגדירים את המסלולים, אפשר ליצור את תרשים הניווט.
val navController = findNavController(R.id.nav_host_fragment)
navController.graph = navController.createGraph(
startDestination = Home
) {
fragment<HomeFragment, Home> {
label = resources.getString(R.string.home_title)
}
fragment<PlantDetailFragment, PlantDetail> {
label = resources.getString(R.string.plant_detail_title)
}
}
בדוגמה זו, שני יעדי מקטעים מוגדרים באמצעות
fragment()
הפונקציה Builder DSL. בפונקציה הזו נדרשים שני סוגים
ארגומנטים
הקצר הזה. התשובות שלך יעזרו לנו להשתפר.
הראשונה, כיתה Fragment
שמספקת את ממשק המשתמש של היעד הזה. להגדרה הזו יש אותה השפעה כמו
הגדרת המאפיין android:name
ביעדי מקטעים מוגדרים
באמצעות XML.
שנית, המסלול. על הטיפוס להיות מסוג ניתן לשינוי מספר סידורי הנרחב מ-Any
. הוא
צריך להכיל את כל ארגומנטים של ניווט שישמשו את היעד הזה,
והסוגים שלהם.
הפונקציה גם מקבלת lambda אופציונליות לתצורה נוספת, כמו וגם תווית היעד, וגם פונקציות של builder מוטמע ארגומנטים וקישורי עומק.
ניווט באמצעות תרשים ה-DSL של Kotlin
לבסוף, אפשר לנווט מhome
אל plant_detail
באמצעות
NavController.navigate()
שיחות:
private fun navigateToPlant(plantId: String) {
findNavController().navigate(route = PlantDetail(id = plantId))
}
ב-PlantDetailFragment
, אפשר לקבל את ארגומנטים של ניווט באמצעות הפונקציה
הנוכחי
NavBackStackEntry
והתקשרות
toRoute
עליו כדי לקבל את המופע של הנתיב.
val plantDetailRoute = findNavController().getBackStackEntry<PlantDetail>().toRoute<PlantDetail>()
val plantId = plantDetailRoute.id
אם PlantDetailFragment
משתמש ב-ViewModel
, צריך להשיג את המופע של המסלול באמצעות
SavedStateHandle.toRoute
.
val plantDetailRoute = savedStateHandle.toRoute<PlantDetail>()
val plantId = plantDetailRoute.id
שאר המדריך מתאר רכיבים נפוצים בתרשים הניווט, יעדים, וכיצד להשתמש בהם כאשר אתם יוצרים את התרשים.
יעדים
Kotlin DSL מספק תמיכה מובנית לשלושה סוגי יעדים:
היעדים Fragment
, Activity
ו-NavGraph
, ולכל אחד מהם יש יעד משלו
פונקציית התוספים המוטבעת זמינה לבנייה ולהגדרה של
היעד.
יעדי מקטעים
fragment()
אפשר להגדיר פרמטרים של פונקציית DSL באמצעות מחלקת המקטעים של ממשק המשתמש,
סוג המסלול שמשמש לזיהוי ייחודי של היעד הזה, ואחריו עמודת lambda
שבו ניתן לספק הגדרות אישיות נוספות כפי שמתואר בקטע ניווט
בקטע של תרשים Kotlin DSL.
fragment<MyFragment, MyRoute> {
label = getString(R.string.fragment_title)
// custom argument types, deepLinks
}
יעד הפעילות
activity()
פונקציית DSL לוקחת פרמטר מסוג 'סוג' עבור המסלול, אבל לא מקבלים פרמטר
כל סיווג פעילות מוטמע. במקום זאת, צריך להגדיר ערך אופציונלי בשדה activityClass
למבדה בסוף. הגמישות הזו מאפשרת להגדיר יעד לפעילות
פעילות שצריך להפעיל באמצעות מודל הענקת גישה משתמע
Intent,
לא יהיה הגיוני. בדומה ליעדים עם מקטעים, אפשר גם
להגדיר תווית, ארגומנטים בהתאמה אישית וקישורי עומק.
activity<MyRoute> {
label = getString(R.string.activity_title)
// custom argument types, deepLinks...
activityClass = MyActivity::class
}
היעד בתרשים הניווט
navigation()
ניתן להשתמש בפונקציית DSL כדי ליצור ניווט בתצוגת עץ
גרפי. הפונקציה הזו לוקחת סוג
של הנתיב שיוקצו לתרשים הזה. יתקבלו גם שני ארגומנטים:
את המסלול של היעד ההתחלתי בגרף, ו-lambda
להגדיר את התרשים. רכיבים חוקיים כוללים יעדים אחרים, ארגומנט בהתאמה אישית
, קישורי עומק ותווית תיאורית
היעד.
התווית הזו יכולה להיות שימושית לקישור תרשים הניווט לרכיבי ממשק משתמש באמצעות
NavigationUI
@Serializable data object HomeGraph
@Serializable data object Home
navigation<HomeGraph>(startDestination = Home) {
// label, other destinations, deep links
}
יעדים מותאמים אישית
אם אתם משתמשים בסוג יעד חדש
שלא תומך ישירות ב-Kotlin DSL, אפשר להוסיף את היעדים האלה
ה-DSL של Kotlin באמצעות
addDestination()
:
// The NavigatorProvider is retrieved from the NavController
val customDestination = navigatorProvider[CustomNavigator::class].createDestination().apply {
route = Graph.CustomDestination.route
}
addDestination(customDestination)
לחלופין, אפשר להשתמש גם באופרטור unary Plus כדי להוסיף יעד מובנה ישירות לתרשים:
// The NavigatorProvider is retrieved from the NavController
+navigatorProvider[CustomNavigator::class].createDestination().apply {
route = Graph.CustomDestination.route
}
הצגת ארגומנטים של יעד
אפשר להגדיר ארגומנטים של יעד כחלק מסיווג הנתיב. האפשרויות האלה יכולות להיות מוגדרים באותו אופן שבו מגדירים כל שיעור ב-Kotlin. הארגומנטים הנדרשים הם מוגדרים כסוגים שאינם ערכי null וארגומנטים אופציונליים מוגדרים כברירת מחדל. ערכים.
המנגנון הבסיסי לייצוג מסלולים והארגומנטים שלהם הוא מחרוזת
מבוסס. השימוש במחרוזות כדי לבנות מודלים של מסלולים מאפשר לשמור את מצב הניווט
שוחזר מהדיסק במהלך הגדרת התצורה
שינויים ותהליך ביוזמת המערכת
מוות. לכן,
כל ארגומנט ניווט צריך להיות ניתן לסידור שלו בסדרה, כלומר צריך להיות לו
שממירה את הייצוג בזיכרון של ערך הארגומנט
String
הסדרה של קוטלין
יישומי פלאגין
יוצרת באופן אוטומטי שיטות סריאליזציה לנתונים בסיסיים
כאשר
ההערה @Serializable
מתווספת לאובייקט.
@Serializable
data class MyRoute(
val id: String,
val myList: List<Int>,
val optionalArg: String? = null
)
fragment<MyFragment, MyRoute>
מתן סוגים מותאמים אישית
כדי להשתמש בסוגי ארגומנטים מותאמים אישית, צריך לספק מחלקה NavType
בהתאמה אישית. הזה
מאפשר לקבוע בדיוק איך הסוג שלכם ינותח מנתיב או מקישור עומק.
לדוגמה, מסלול שמשמש להגדרה של מסך חיפוש יכול להכיל מחלקה שמייצג את הפרמטרים של החיפוש:
@Serializable
data class SearchRoute(val parameters: SearchParameters)
@Serializable
data class SearchParameters(
val searchQuery: String,
val filters: List<String>
)
אפשר לכתוב NavType
בהתאמה אישית כך:
val SearchParametersType = object : NavType<SearchParameters>(
isNullableAllowed = false
) {
override fun put(bundle: Bundle, key: String, value: SearchParameters) {
bundle.putParcelable(key, value)
}
override fun get(bundle: Bundle, key: String): SearchParameters {
return bundle.getParcelable(key) as SearchParameters
}
override fun serializeAsValue(value: SearchParameters): String {
// Serialized values must always be Uri encoded
return Uri.encode(Json.encodeToString(value))
}
override fun parseValue(value: String): SearchParameters {
// Navigation takes care of decoding the string
// before passing it to parseValue()
return Json.decodeFromString<SearchParameters>(value)
}
}
לאחר מכן אפשר להשתמש בו ב-Kotlin DSL כמו כל סוג אחר:
fragment<SearchFragment, SearchRoute> {
label = getString(R.string.plant_search_title)
typeMap = mapOf(typeOf<SearchParameters>() to SearchParametersType)
}
כשמנווטים ליעד, יוצרים מופע של המסלול:
val params = SearchParameters("rose", listOf("available"))
navController.navigate(route = SearchRoute(params))
אפשר לקבל את הפרמטר מהמסלול ביעד:
val searchRoute = navController().getBackStackEntry<SearchRoute>().toRoute<SearchRoute>()
val params = searchRoute.parameters
קישורי עומק
אפשר להוסיף קישורי עומק לכל יעד, בדיוק כמו שמוסיפים קישורי עומק תרשים ניווט. כל אותם התהליכים שמוגדרים ביצירת קישור עומק של יעד חלים על התהליך ליצירת קישור עומק באמצעות Kotlin DSL.
כשיוצרים קישור עומק מרומז
אבל אין לכם משאב ניווט בפורמט XML שניתן לנתח
רכיבי <deepLink>
. לכן, לא ניתן להסתמך על הצבת <nav-graph>
בקובץ AndroidManifest.xml
וצריך להוסיף במקום זאת כוונת רכישה
מסננים לפעילות שלכם באופן ידני. הכוונה
המסנן שמספקים צריך להתאים לנתיב הבסיסי, לפעולה ול-mimetype של
בקישורי העומק של האפליקציה.
קישורי עומק מתווספים ליעד על ידי קריאה לפונקציה deepLink
שבפנים
הלמבדה של היעד. הוא מקבל את המסלול כסוג פרמטר,
basePath
לנתיב הבסיס של כתובת ה-URL שמשמשת לקישור העומק.
ניתן גם להוסיף פעולה ו-mimetype באמצעות
deepLinkBuilder
למבדה בסוף.
הדוגמה הבאה יוצרת URI של קישור עומק עבור היעד Home
.
@Serializable data object Home
fragment<HomeFragment, Home>{
deepLink<Home>(basePath = "www.example.com/home"){
// Optionally, specify the action and/or mime type that this destination
// supports
action = "android.intent.action.MY_ACTION"
mimeType = "image/*"
}
}
פורמט URI
פורמט ה-URI של קישור עומק נוצר באופן אוטומטי משדות הנתיב באמצעות הכללים הבאים:
- הפרמטרים הנדרשים מתווספים כפרמטרים של נתיב (לדוגמה:
/{id}
) - פרמטרים עם ערך ברירת מחדל (פרמטרים אופציונליים) מצורפים כ-query
פרמטרים (לדוגמה:
?name={name}
) - אוספים מתווספים כפרמטרים של שאילתה (לדוגמה:
?items={value1}&items={value2}
) - סדר הפרמטרים תואם לסדר השדות במסלול
לדוגמה, סוג המסלול הבא:
@Serializable data class PlantDetail(
val id: String,
val name: String,
val colors: List<String>,
val latinName: String? = null,
)
נוצר פורמט URI של:
basePath/{id}/{name}/?colors={color1}&colors={color2}&latinName={latinName}
אין הגבלה על מספר קישורי העומק שאפשר להוסיף. בכל פעם שמתקשרים
deepLink()
קישור עומק חדש מצורף לרשימה שנשמרה עבור היעד הזה.
מגבלות
הפלאגין Safe Args הוא
לא תואם ל-Kotlin DSL, כי הפלאגין מחפש קובצי משאבים של XML כדי
ליצור Directions
ו-Arguments
מחלקות.