ทักษะ Android
ดูใน GitHubJetpack Navigation 3
android skills add navigation-3หากต้องการย้ายข้อมูลแอปจาก Navigation 2 ไปยัง Navigation 3 ให้ทำตามขั้นตอนต่อไปนี้
- เพิ่มการอ้างอิง Navigation 3
- อัปเดตเส้นทางการนำทางเพื่อใช้
NavKeyอินเทอร์เฟซ - สร้างคลาสเพื่อเก็บและแก้ไขสถานะการนำทาง
- แทนที่
NavControllerด้วยคลาสต่อไปนี้ - ย้ายปลายทางจาก
NavGraphของNavHostไปยังentryProvider - แทนที่
NavHostด้วยNavDisplay - นำการอ้างอิง Navigation 2 ออก
การเตรียมพร้อม
ส่วนต่อไปนี้จะอธิบายข้อกำหนดเบื้องต้นสำหรับการย้ายข้อมูลและสมมติฐาน เกี่ยวกับโปรเจ็กต์ของคุณ นอกจากนี้ ยังครอบคลุมฟีเจอร์ที่รองรับสำหรับการ ย้ายข้อมูลและฟีเจอร์ที่ไม่รองรับด้วย
สิ่งที่ต้องมีก่อน
- คุณต้องใช้
compileSdkตั้งแต่ 36 ขึ้นไป - คุณควรทำความคุ้นเคยกับคำศัพท์เกี่ยวกับการนำทาง
- ปลายทางคือฟังก์ชันที่ประกอบกันได้ Navigation 3 ออกแบบมาสำหรับ Compose โดยเฉพาะ หากต้องการใช้ Fragment และ View ใน Compose โปรดดูการใช้ View ใน Compose
- เส้นทางมีการพิมพ์อย่างเข้มงวด หากใช้เส้นทางที่อิงตามสตริง ให้ย้ายข้อมูลไปยัง เส้นทางที่ปลอดภัยต่อประเภทก่อน (ตัวอย่าง)
- ไม่บังคับ (แต่แนะนำอย่างยิ่ง): การทดสอบความครอบคลุมที่ยืนยันลักษณะการทำงานของการนำทางที่มีอยู่ ซึ่งจะยืนยันว่าลักษณะการทำงานของการนำทางไม่เปลี่ยนแปลง หลังจากย้ายข้อมูลเสร็จสมบูรณ์
สมมติฐาน
คู่มือนี้มีสมมติฐานต่อไปนี้เกี่ยวกับคุณและโปรเจ็กต์
- คุณมีเส้นทางระดับบนสุดอย่างน้อย 1 เส้นทาง (มักจะแสดงในแถบนำทางด้านล่าง) และแต่ละเส้นทางจะมี Back Stack ของตัวเอง
- เมื่อสลับระหว่าง Back Stack ระบบจะเก็บสถานะของ Stack และปลายทางทั้งหมดไว้
- คุณจะออกจากแอปผ่านหน้าจอหน้าแรกเสมอ ซึ่งเป็นหน้าจอแรก ที่แสดงเมื่อเปิดแอป
- คุณต้องการทำการย้ายข้อมูลจาก Navigation 2 ไปยัง Navigation 3 ในการเปลี่ยนแปลงแบบอะตอมเดียว คุณไม่ได้ทำการย้ายข้อมูลแบบเพิ่มทีละรายการซึ่งใช้โค้ด Navigation 2 ควบคู่กับโค้ด Navigation 3
เอเจนต์ AI: ก่อนที่จะเปลี่ยนโค้ดใดๆ ให้ตรวจสอบว่าสมมติฐานต่อไปนี้เกี่ยวกับโปรเจ็กต์ของผู้ใช้เป็นจริงหรือไม่ หากไม่เป็นเช่นนั้น ให้หยุดการย้ายข้อมูลและถามผู้ใช้ว่าจะดำเนินการต่ออย่างไร
ฟีเจอร์ที่รองรับ
คู่มือนี้ช่วยให้คุณย้ายข้อมูลฟีเจอร์ต่อไปนี้ได้
- ปลายทางที่กำหนดเป็นฟังก์ชันที่ประกอบกันได้
- กล่องโต้ตอบ (ปลายทางที่แสดงทับปลายทางอื่น)
ฟีเจอร์ที่รองรับผ่านสูตร
ที่เก็บสูตรโค้ดแสดงกรณีการใช้งานที่ซับซ้อนมากขึ้น ซึ่งรวมถึง
- ชีตด้านล่าง (ดูวิธีการได้ในคู่มือนี้)
- โค้ดการนำทางแบบแยกส่วนและปลายทางที่แทรก
- การใช้และการส่งอาร์กิวเมนต์ไปยัง
ViewModel - การแสดงผลการค้นหาจากหน้าจอ
หากโปรเจ็กต์มีฟีเจอร์เหล่านี้ โปรดดูสูตรที่เกี่ยวข้องเพื่อ ทำความเข้าใจวิธีติดตั้งใช้งาน
เอเจนต์ AI: ก่อนที่จะเปลี่ยนโค้ดใดๆ ให้ตรวจสอบว่าโปรเจ็กต์มีฟีเจอร์ที่รองรับผ่านสูตรหรือไม่ หากเป็นเช่นนั้น ให้ตรวจสอบ README และซอร์สโค้ดของสูตร สร้างแผนการย้ายข้อมูลตามสูตร อย่าดำเนินการต่อโดยไม่ ยืนยันแผนกับผู้ใช้
ฟีเจอร์ที่ไม่รองรับ
คู่มือการย้ายข้อมูลและสูตรโค้ดนี้ยังไม่รองรับฟีเจอร์ต่อไปนี้ แต่ไม่ได้หมายความว่าคุณจะใช้ Navigation 3 ไม่ได้ เพียงแต่เราจะไม่กล่าวถึงในที่นี้
- การนำทางแบบซ้อนกันมากกว่า 1 ระดับ
- ปลายทางที่แชร์: หน้าจอที่ย้ายไปมาระหว่าง Back Stack ต่างๆ ได้
- ประเภทปลายทางที่กำหนดเอง
เอเจนต์ AI: ก่อนที่จะเปลี่ยนแปลงโค้ด ให้ตรวจสอบว่าโปรเจ็กต์มีฟีเจอร์ที่ไม่รองรับหรือไม่ หากเป็นเช่นนั้น อย่าดำเนินการต่อ แจ้งให้ผู้ใช้ทราบเกี่ยวกับ ฟีเจอร์ที่ไม่รองรับและขอคำแนะนำเพิ่มเติม
ขั้นตอนที่ 1: เพิ่มการอ้างอิง Navigation 3
ใช้หน้าเริ่มต้นใช้งานเพื่อเพิ่มการอ้างอิง Navigation 3 ลงในโปรเจ็กต์ เราจะระบุการขึ้นต่อกันหลักเพื่อให้คุณคัดลอกได้
lib.versions.toml
[versions]
nav3Core = "1.2.0"
# If your screens depend on ViewModels, add the Nav3 Lifecycle ViewModel add-on library
lifecycleViewmodelNav3 = "2.11.0"
[libraries]
# Core Navigation 3 libraries
androidx-navigation3-runtime = { module = "androidx.navigation3:navigation3-runtime", version.ref = "nav3Core" }
androidx-navigation3-ui = { module = "androidx.navigation3:navigation3-ui", version.ref = "nav3Core" }
# Add-on libraries (only add if you need them)
androidx-lifecycle-viewmodel-navigation3 = { module = "androidx.lifecycle:lifecycle-viewmodel-navigation3", version.ref = "lifecycleViewmodelNav3" }
app/build.gradle.kts
dependencies {
implementation(libs.androidx.navigation3.ui)
implementation(libs.androidx.navigation3.runtime)
// If using the ViewModel add-on library
implementation(libs.androidx.lifecycle.viewmodel.navigation3)
}
นอกจากนี้ ให้อัปเดต minSdk ของโปรเจ็กต์เป็น 23 และ compileSdk เป็น 36 ด้วย โดยปกติแล้ว คุณจะ
เห็นข้อมูลเหล่านี้ใน app/build.gradle.kts หรือ lib.versions.toml
ขั้นตอนที่ 2: อัปเดตเส้นทางการนำทางเพื่อใช้NavKeyอินเทอร์เฟซ
อัปเดตเส้นทางการนำทางทุกเส้นทางเพื่อให้ใช้NavKey
อินเทอร์เฟซ ซึ่งจะช่วยให้คุณใช้ rememberNavBackStack เพื่อช่วยบันทึก
สถานะการนำทางได้
ก่อน:
@Serializable data object RouteA
หลัง:
@Serializable data object RouteA : NavKey
ขั้นตอนที่ 3: สร้างคลาสเพื่อจัดเก็บและแก้ไขสถานะการนำทาง
ขั้นตอนที่ 3.1: สร้างตัวเก็บสถานะการนำทาง
คัดลอกโค้ดต่อไปนี้ลงในไฟล์ชื่อ NavigationState.kt เพิ่มชื่อแพ็กเกจ
ให้ตรงกับโครงสร้างโปรเจ็กต์
// package com.example.project import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSerializable import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshots.SnapshotStateList import androidx.compose.runtime.toMutableStateList import androidx.navigation3.runtime.NavBackStack import androidx.navigation3.runtime.NavEntry import androidx.navigation3.runtime.NavKey import androidx.navigation3.runtime.rememberDecoratedNavEntries import androidx.navigation3.runtime.rememberNavBackStack import androidx.navigation3.runtime.rememberSaveableStateHolderNavEntryDecorator import androidx.navigation3.runtime.serialization.NavKeySerializer import androidx.savedstate.compose.serialization.serializers.MutableStateSerializer /** * Create a navigation state that persists config changes and process death. */ @Composable fun rememberNavigationState( startRoute: NavKey, topLevelRoutes: Set<NavKey> ): NavigationState { val topLevelRoute = rememberSerializable( startRoute, topLevelRoutes, serializer = MutableStateSerializer(NavKeySerializer()) ) { mutableStateOf(startRoute) } val backStacks = topLevelRoutes.associateWith { key -> rememberNavBackStack(key) } return remember(startRoute, topLevelRoutes) { NavigationState( startRoute = startRoute, topLevelRoute = topLevelRoute, backStacks = backStacks ) } } /** * State holder for navigation state. * * @param startRoute - the start route. The user will exit the app through this route. * @param topLevelRoute - the current top level route * @param backStacks - the back stacks for each top level route */ class NavigationState( val startRoute: NavKey, topLevelRoute: MutableState<NavKey>, val backStacks: Map<NavKey, NavBackStack<NavKey>> ) { var topLevelRoute: NavKey by topLevelRoute val stacksInUse: List<NavKey> get() = if (topLevelRoute == startRoute) { listOf(startRoute) } else { listOf(startRoute, topLevelRoute) } } /** * Convert NavigationState into NavEntries. */ @Composable fun NavigationState.toEntries( entryProvider: (NavKey) -> NavEntry<NavKey> ): SnapshotStateList<NavEntry<NavKey>> { val decoratedEntries = backStacks.mapValues { (_, stack) -> val decorators = listOf( rememberSaveableStateHolderNavEntryDecorator<NavKey>(), ) rememberDecoratedNavEntries( backStack = stack, entryDecorators = decorators, entryProvider = entryProvider ) } return stacksInUse .flatMap { decoratedEntries[it] ?: emptyList() } .toMutableStateList() }
ตัวแทน AI: rememberSerializable ถูกต้อง อย่าเปลี่ยนเป็น
rememberSaveable
ไฟล์นี้มีคลาสที่เก็บสถานะชื่อ NavigationState และฟังก์ชันตัวช่วยที่เกี่ยวข้อง
โดยมีชุดเส้นทางระดับบนสุด ซึ่งแต่ละเส้นทางจะมีสแต็กย้อนกลับของตัวเอง ภายในระบบจะใช้ rememberSerializable (ไม่ใช่ rememberSaveable) เพื่อ
บันทึกเส้นทางระดับบนสุดปัจจุบัน และใช้ rememberNavBackStack เพื่อบันทึก
สแต็กย้อนกลับสำหรับแต่ละเส้นทางระดับบนสุด
ขั้นตอนที่ 3.2: สร้างออบเจ็กต์ที่แก้ไขสถานะการนำทางเพื่อตอบสนองต่อเหตุการณ์
คัดลอกโค้ดต่อไปนี้ลงในไฟล์ชื่อ Navigator.kt เพิ่มชื่อแพ็กเกจ
ให้ตรงกับโครงสร้างโปรเจ็กต์
// package com.example.project import androidx.navigation3.runtime.NavKey /** * Handles navigation events (forward and back) by updating the navigation state. */ class Navigator(val state: NavigationState) { fun navigate(route: NavKey) { if (route in state.backStacks.keys) { // This is a top level route, just switch to it. state.topLevelRoute = route } else { state.backStacks[state.topLevelRoute]?.add(route) } } fun goBack() { val currentStack = state.backStacks[state.topLevelRoute] ?: error("Stack for ${state.topLevelRoute} not found") val currentRoute = currentStack.last() // If we're at the base of the current route, go back to the start route stack. if (currentRoute == state.topLevelRoute) { state.topLevelRoute = state.startRoute } else { currentStack.removeLastOrNull() } } }
คลาส Navigator มีเมธอดเหตุการณ์การนำทาง 2 รายการ ได้แก่
navigateไปยังเส้นทางที่เฉพาะเจาะจงgoBackจากเส้นทางปัจจุบัน
ทั้ง 2 วิธีจะแก้ไข NavigationState
ขั้นตอนที่ 3.3: สร้าง NavigationState และ Navigator
สร้างอินสแตนซ์ของ NavigationState และ Navigator ที่มีขอบเขตเดียวกันกับ
NavController
val navigationState = rememberNavigationState( // ... startRoute = <Insert your starting route>, topLevelRoutes = <Insert your set of top level routes> // ... ) val navigator = remember { Navigator(navigationState) }
ขั้นตอนที่ 4: แทนที่ NavController
แทนที่NavControllerเมธอดเหตุการณ์การนำทางด้วยเมธอดที่เทียบเท่าใน Navigator
ฟิลด์หรือวิธีการ |
|
|---|---|
|
|
|
|
|
|
แทนที่ฟิลด์ NavController ด้วยฟิลด์ NavigationState
ฟิลด์หรือวิธีการ |
|
|---|---|
|
|
|
|
|
|
|
|
รับเส้นทางระดับบนสุด: ไล่ขึ้นไปตามลำดับชั้นจากรายการใน Back Stack ปัจจุบันเพื่อค้นหา |
|
ใช้ NavigationState.topLevelRoute เพื่อระบุรายการที่เลือกอยู่ในแถบนำทาง
ในขณะนี้
ก่อน:
// ... val isSelected = navController.currentBackStackEntryAsState().value?.destination.isRouteInHierarchy(key::class) // ... fun NavDestination?.isRouteInHierarchy(route: KClass<*>) = this?.hierarchy?.any { it.hasRoute(route) } ?: false
หลัง:
val isSelected = key == navigationState.topLevelRoute
ตรวจสอบว่าคุณได้นำการอ้างอิงถึง NavController ทั้งหมดออกแล้ว รวมถึง
การนำเข้าทั้งหมด
ขั้นตอนที่ 4.1 ย้ายตรรกะที่รับรู้ถึงวงจร
ใน Navigation 2 NavBackStackEntry จะใช้ LifecycleOwner ซึ่งช่วยให้คุณ
ฟังเหตุการณ์วงจร หรือรวบรวมโฟลว์ในลักษณะที่รับรู้ถึงวงจรได้โดยใช้
navController.currentBackStackEntry
ใน Navigation 3 NavDisplay จะมี LifecycleOwner
ที่กำหนดขอบเขตรายการผ่าน LocalLifecycleOwner.current ไปยังเนื้อหาที่ใช้ได้กับ Composable ของแต่ละปลายทาง
ดูข้อมูลเพิ่มเติมได้ที่วงจรของปลายทาง
คุณควรดำเนินการที่คำนึงถึงวงจรโดยตรงภายในเนื้อหาที่ประกอบได้ของปลายทางโดยอ้างอิง LocalLifecycleOwner.current
ตัวอย่างเช่น หากคุณรวบรวมโฟลว์ในลักษณะที่รับรู้ถึงวงจรโดยใช้รายการย้อนกลับ
ก่อน:
// In your destination screen or host val lifecycleOwner = navController.currentBackStackEntry!! val state by flow.collectAsStateWithLifecycle(lifecycleOwner = lifecycleOwner)
หลัง:
// Inside the destination composable val state by flow.collectAsStateWithLifecycle()
ขั้นตอนที่ 4.2 ย้ายข้อมูลการส่งผลลัพธ์
ใน Navigation 2 ปลายทางจะส่งผลลัพธ์กลับไปยังปลายทางก่อนหน้าโดยใช้
SavedStateHandle ใน NavBackStackEntry เนื่องจาก SavedStateHandle ได้รับการสนับสนุนโดยสถานะอินสแตนซ์ที่บันทึกไว้ ข้อมูลที่ส่งคืนจึงยังคงอยู่แม้ว่ากระบวนการจะสิ้นสุดลงโดยอัตโนมัติ
ก่อน:
// Sender destination: navController.previousBackStackEntry?.savedStateHandle?.set("contact_key", contact) navController.popBackStack() // Receiver destination: val lifecycleOwner = LocalLifecycleOwner.current navController.currentBackStackEntry?.savedStateHandle ?.getLiveData<Contact>("contact_key") ?.observe(lifecycleOwner) { contact -> viewModel.onRecipientSelected(contact) }
ใน Navigation 3 ให้เพิ่ม
rememberResultEventBusNavEntryDecorator() ไปยัง
NavDisplay.entryDecorators ในentryProvider
การแมปของปลายทางผู้ส่ง ให้เรียก LocalResultEventBus.current
และเรียกใช้ sendResult() ในปลายทางที่รับ ให้ใช้
ResultEffect เพื่อส่งต่อเหตุการณ์ไปยัง ViewModel หรือ
ทริกเกอร์ผลข้างเคียง
หลัง:
// Sender destination (in entryProvider): entry<ContactPickerRoute> { val resultBus = LocalResultEventBus.current ContactPickerScreen( onContactSelected = { contact -> resultBus.sendResult<Contact>(result = contact) navigator.goBack() } ) } // Receiver destination: @Composable fun ComposeMessageScreen(viewModel: ComposeMessageViewModel = viewModel()) { ResultEffect<Contact> { contact -> viewModel.onRecipientSelected(contact) } ComposeMessageContent(recipient = viewModel.recipient) }
สำหรับการสังเกตการณ์ตามสถานะ คุณสามารถเรียกใช้ resultBus.conflateAsState() ได้ ดูรายละเอียดเพิ่มเติมได้ที่แสดงผลลัพธ์
ขั้นตอนที่ 5: ย้ายปลายทางจาก NavHost ของ NavGraph ไปยัง entryProvider
ใน Navigation 2 คุณกำหนดปลายทาง
โดยใช้ NavGraphBuilder DSL
ซึ่งมักจะอยู่ภายใน Lambda ต่อท้ายของ NavHost โดยทั่วไปจะใช้ฟังก์ชันส่วนขยายที่นี่ตามที่อธิบายไว้ในแคปซูลโค้ดการนำทาง
ใน Navigation 3 คุณจะกำหนดปลายทางโดยใช้ entryProvider entryProvider นี้จะเปลี่ยนเส้นทางไปยัง NavEntry สิ่งสำคัญคือ
entryProvider ไม่ได้กำหนดความสัมพันธ์แบบแม่-ลูกระหว่างรายการ
ในคู่มือการย้ายข้อมูลนี้ ความสัมพันธ์แบบหลักกับย่อยจะได้รับการจำลอง ดังนี้
NavigationStateมีชุดเส้นทางระดับบนสุด (เส้นทางหลัก) และสแต็กสำหรับแต่ละเส้นทาง โดยจะติดตามเส้นทางระดับบนสุดปัจจุบันและสแต็กที่เชื่อมโยง- เมื่อไปยังเส้นทางใหม่
Navigatorจะตรวจสอบว่าเส้นทางนั้นเป็น เส้นทางระดับบนสุดหรือไม่ หากเป็นเช่นนั้น ระบบจะอัปเดตเส้นทางและสแต็กระดับบนสุดปัจจุบัน หากไม่ใช่ ก็จะเป็นเส้นทางย่อยและจะเพิ่มลงในสแต็กปัจจุบัน
ขั้นตอนที่ 5.1: สร้าง entryProvider
สร้าง entryProvider โดยใช้ DSL ที่ขอบเขตเดียวกันกับ
NavigationState
val entryProvider = entryProvider<NavKey> { }
ขั้นตอนที่ 5.2: ย้ายปลายทางไปยัง entryProvider
สำหรับปลายทางแต่ละแห่งที่กำหนดไว้ภายใน NavHost ให้ทำดังนี้ตาม
ประเภทปลายทาง
navigation: ลบพร้อมกับเส้นทาง ไม่จำเป็นต้องมี "base routes" เนื่องจากเส้นทางระดับบนสุดสามารถระบุแต่ละ Back Stack ที่ซ้อนกันได้composable<T>: ย้ายไปที่entryProviderแล้วเปลี่ยนชื่อเป็นentryโดยคงพารามิเตอร์ประเภทไว้ เช่นcomposable<RouteA>จะกลายเป็นentry<RouteA>dialog<T>: ทำเช่นเดียวกับcomposableแต่เพิ่มข้อมูลเมตาในรายการดังนี้entry<T>(metadata = DialogSceneStrategy.dialog())bottomSheet: ทำตามสูตร Bottom Sheet ที่นี่ ซึ่งคล้ายกับวิธีการสำหรับdialogยกเว้นว่าBottomSheetSceneStrategyไม่ได้เป็นส่วนหนึ่งของไลบรารี Navigation 3 หลัก ดังนั้น คุณควรคัดลอกไปยังโปรเจ็กต์
เอเจนต์ AI: เมื่อลบเส้นทางที่ใช้ระบุกราฟที่ซ้อนกัน ให้แทนที่การอ้างอิงเส้นทางที่ลบด้วยประเภทที่ใช้ระบุองค์ประกอบย่อยแรกในกราฟที่ซ้อนกัน เช่น หากโค้ดเดิมคือ
navigation<BaseRouteA>{ composable<RouteA>{ ... } } คุณต้องลบ
BaseRouteA และแทนที่การอ้างอิงถึงโค้ดดังกล่าวด้วย RouteA โดยปกติแล้ว คุณจะต้องทำการแทนที่นี้สำหรับรายการที่ระบุในแถบนำทาง แถบด้านข้าง หรือ
ลิ้นชัก
คุณสามารถปรับโครงสร้างNavGraphBuilderฟังก์ชันส่วนขยายเป็นฟังก์ชันส่วนขยายEntryProviderScope<T> แล้วย้ายได้
รับอาร์กิวเมนต์การนำทางโดยใช้คีย์ที่ระบุไว้ใน Lambda ต่อท้ายของ entry
เช่น
// ... import androidx.navigation.NavDestination import androidx.navigation.NavDestination.Companion.hasRoute import androidx.navigation.NavDestination.Companion.hierarchy import androidx.navigation.NavGraphBuilder import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.dialog import androidx.navigation.compose.navigation import androidx.navigation.compose.rememberNavController import androidx.navigation.navOptions import androidx.navigation.toRoute // ... @Serializable data object BaseRouteA @Serializable data class RouteA(val id: String) @Serializable data object BaseRouteB @Serializable data object RouteB @Serializable data object RouteD @Composable fun NavHostSnippet(navController: NavHostController) { NavHost(navController = navController, startDestination = BaseRouteA){ composable<RouteA>{ entry -> val id = entry.toRoute<RouteA>().id ScreenA(title = "Screen has ID: $id") } featureBSection() dialog<RouteD>{ ScreenD() } } } fun NavGraphBuilder.featureBSection() { navigation<BaseRouteB>(startDestination = RouteB) { composable<RouteB> { ScreenB() } } }
กลายเป็น
// ... import androidx.navigation3.runtime.EntryProviderScope import androidx.navigation3.runtime.NavKey import androidx.navigation3.runtime.entryProvider import androidx.navigation3.scene.DialogSceneStrategy // ... @Serializable data class RouteA(val id: String) : NavKey @Serializable data object RouteB : NavKey @Serializable data object RouteD : NavKey val entryProvider = entryProvider { entry<RouteA>{ key -> ScreenA(title = "Screen has ID: ${key.id}") } featureBSection() entry<RouteD>(metadata = DialogSceneStrategy.dialog()){ ScreenD() } } fun EntryProviderScope<NavKey>.featureBSection() { entry<RouteB> { ScreenB() } }
ขั้นตอนที่ 6: แทนที่ NavHost ด้วย NavDisplay
แทนที่ NavHost ด้วย NavDisplay
- ลบ
NavHostและแทนที่ด้วยNavDisplay - ระบุ
entries = navigationState.toEntries(entryProvider)เป็นพารามิเตอร์ ซึ่งจะแปลงสถานะการนำทางเป็นรายการที่NavDisplayแสดง โดยใช้entryProvider - เชื่อมต่อ
NavDisplay.onBackกับnavigator.goBack()ซึ่งจะทำให้navigatorอัปเดตสถานะการนำทางเมื่อตัวแฮนเดิลย้อนกลับในตัวของNavDisplayเสร็จสมบูรณ์ - หากมีปลายทางของกล่องโต้ตอบ ให้เพิ่ม
DialogSceneStrategyไปยังพารามิเตอร์NavDisplaysceneStrategies
เช่น
NavDisplay( entries = navigationState.toEntries(entryProvider), onBack = { navigator.goBack() }, sceneStrategies = remember { listOf(DialogSceneStrategy()) } )
ขั้นตอนที่ 7: ย้ายข้อมูล Deep Link
ใน Navigation 2 มีการกำหนด Deep Link ภายในกราฟการนำทางโดยตรง
โดยใช้พารามิเตอร์ deepLinks ของปลายทาง
ใน Navigation 3 ระบบจะจัดการ Deep Link โดยไม่ขึ้นอยู่กับ UI ของการนำทาง คุณ กำหนด DeepLinkMatcher และจับคู่คำขอที่เข้ามาในกิจกรรมเพื่อ สร้าง Back Stack เริ่มต้น
ก่อน:
ใน Navigation 2 คุณอาจกำหนด Deep Link ดังนี้
composable<RouteA>( deepLinks = listOf( navDeepLink { uriPattern = "www.example.com/user/{id}" } ) ) { // ... }
หลัง:
ใน Navigation 3 คุณจะกำหนด UriDeepLinkMatcher สำหรับเส้นทางได้ดังนี้
val userMatcher = UriDeepLinkMatcher( DeepLinkUri("www.example.com/user/{id}"), serializer<RouteA>() )
จากนั้นใน onCreate ของกิจกรรม (และ onNewIntent) คุณจะจับคู่ Intent ขาเข้าและเริ่มต้น Back Stack ดังนี้
val deepLinkMatchers: List<DeepLinkMatcher<*, *>> = listOf( userMatcher, ) class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val request = DeepLinkRequest(intent = intent) val matchResult = deepLinkMatchers .mapNotNull { it.match(request) } .maxOrNull() val backStack = when (matchResult) { null -> listOf(HomeKey) is BackStackMatchResult<*, *> -> { @Suppress("UNCHECKED_CAST") matchResult.backStack as List<NavKey> } else -> listOf(matchResult.key) } // Use backStack with NavDisplay } }
ประเภทอาร์กิวเมนต์ที่กำหนดเอง
ใน Navigation 2 คุณจัดการประเภทอาร์กิวเมนต์ที่กำหนดเองหรือของบุคคลที่สาม (เช่น
LocalDateTime) โดยใช้การติดตั้งใช้งาน NavType ที่กำหนดเองและ typeMap
ใน Navigation 3 ให้กำหนด DeepLinkSerializer เพื่อยกเลิกการซีเรียลไลซ์ประเภทที่กำหนดเองหรือ
ประเภทของบุคคลที่สามจากพารามิเตอร์ URI ดูรายละเอียดได้ที่
การซีเรียลไลซ์ที่กำหนดเองด้วย DeepLinkSerializer
สำหรับกรณีการใช้งานขั้นสูง รวมถึงสแต็กย้อนกลับสังเคราะห์และตัวจับคู่ที่กำหนดเอง โปรดดูคำแนะนำรองรับ Deep Link
ขั้นตอนที่ 8: นำการอ้างอิง Navigation 2 ออก
นำการนำเข้า Navigation 2 และทรัพยากร Dependency ของไลบรารีทั้งหมดออก
สรุป
ยินดีด้วย ตอนนี้ระบบได้ย้ายข้อมูลโปรเจ็กต์ของคุณไปยังการนำทาง 3 แล้ว หากคุณหรือเอเจนต์ AI พบปัญหาในการใช้คู่มือนี้ โปรดรายงานข้อบกพร่องที่นี่