เมื่อใช้ Kotlin DSL เพื่อสร้างกราฟ โดยเก็บปลายทางและ เหตุการณ์การไปยังส่วนต่างๆ ในไฟล์เดียวอาจทำให้จัดการได้ยาก นี่คือ โดยเฉพาะหากคุณมีฟีเจอร์อิสระหลายรายการ
ดึงข้อมูลปลายทาง
คุณควรย้ายปลายทางไปยังส่วนขยาย NavGraphBuilder
 ลูกค้าควรอาศัยอยู่ใกล้กับเส้นทางที่ระบุตนเอง และ
หน้าจอที่แสดง ตัวอย่างเช่น ลองพิจารณาโค้ดระดับแอปต่อไปนี้
ที่สร้างปลายทางซึ่งแสดงรายการรายชื่อติดต่อ ดังนี้
// MyApp.kt
@Serializable
object Contacts
@Composable
fun MyApp() {
  ...
  NavHost(navController, startDestination = Contacts) {
    composable<Contacts> { ContactsScreen( /* ... */ ) }
  }
}
คุณควรย้ายโค้ดเฉพาะสำหรับการนำทางไปไว้ในไฟล์แยกต่างหาก
// ContactsNavigation.kt
@Serializable
object Contacts
fun NavGraphBuilder.contactsDestination() {
    composable<Contacts> { ContactsScreen( /* ... */ ) }
}
// MyApp.kt
@Composable
fun MyApp() {
  ...
  NavHost(navController, startDestination = Contacts) {
     contactsDestination()
  }
}
คำจำกัดความเส้นทางและจุดหมายนั้นจะแยกออกจากแอปหลักและ
คุณก็สามารถอัปเดตแยกกันได้ แอปหลักจะขึ้นอยู่กับแอปเดียวเท่านั้น
ของส่วนขยาย ในกรณีนี้ จะ
NavGraphBuilder.contactsDestination()
ฟังก์ชันส่วนขยาย NavGraphBuilder จะสร้างบริดจ์ระหว่างสถานะแบบไม่เก็บสถานะ
ฟังก์ชัน Composable ระดับหน้าจอและตรรกะเฉพาะการนำทาง เลเยอร์นี้สามารถ
จะระบุที่มาของรัฐและวิธีที่คุณจัดการกับเหตุการณ์ด้วย
ตัวอย่าง
ข้อมูลโค้ดต่อไปนี้จะแนะนำปลายทางใหม่เพื่อแสดงข้อมูลติดต่อ รายละเอียด และอัปเดตปลายทางรายการที่อยู่ติดต่อที่มีอยู่ให้ แสดง เหตุการณ์การนำทางเพื่อแสดงรายละเอียดของรายชื่อติดต่อ
ต่อไปนี้เป็นชุดหน้าจอทั่วไปที่สามารถinternalเป็นโมดูลของตัวเองได้
โมดูลอื่นๆ ไม่สามารถเข้าถึงได้:
// ContactScreens.kt
// Displays a list of contacts
@Composable
internal fun ContactsScreen(
  uiState: ContactsUiState,
  onNavigateToContactDetails: (contactId: String) -> Unit
) { ... }
// Displays the details for an individual contact
@Composable
internal fun ContactDetailsScreen(contact: ContactDetails) { ... }
สร้างปลายทาง
ฟังก์ชันส่วนขยาย NavGraphBuilder ต่อไปนี้จะสร้างปลายทาง
ซึ่งแสดง ContactsScreen Composable นอกจากนี้ ยังเชื่อมต่อ
หน้าจอด้วย ViewModel ที่ให้สถานะ UI ของหน้าจอและจัดการ
แต่ใช้ตรรกะทางธุรกิจที่
เกี่ยวข้องกับหน้าจอ
เหตุการณ์การนําทาง เช่น การไปยังปลายทางของรายละเอียดการติดต่อนั้น
เห็นแก่ผู้โทรแทนที่จะให้ ViewModel จัดการ
// ContactsNavigation.kt
@Serializable
object Contacts
// Adds contacts destination to `this` NavGraphBuilder
fun NavGraphBuilder.contactsDestination(
  // Navigation events are exposed to the caller to be handled at a higher level
  onNavigateToContactDetails: (contactId: String) -> Unit
) {
  composable<Contacts> {
    // The ViewModel as a screen level state holder produces the screen
    // UI state and handles business logic for the ConversationScreen
    val viewModel: ContactsViewModel = hiltViewModel()
    val uiState = viewModel.uiState.collectAsStateWithLifecycle()
    ContactsScreen(
      uiState,
      onNavigateToContactDetails
    )
  }
}
คุณสามารถใช้วิธีการเดียวกันนี้เพื่อสร้างปลายทางที่แสดง
ContactDetailsScreen ในกรณีนี้ แทนที่จะได้รับสถานะ UI จาก
ดูโมเดลนี้ได้จาก NavBackStackEntry โดยตรง
// ContactsNavigation.kt
@Serializable
internal data class ContactDetails(val id: String)
fun NavGraphBuilder.contactDetailsScreen() {
  composable<ContactDetails> { navBackStackEntry ->
    ContactDetailsScreen(contact = navBackStackEntry.toRoute())
  }
}
สรุปเหตุการณ์การนำทาง
เช่นเดียวกับการห่อหุ้มปลายทาง คุณสามารถห่อหุ้มปลายทางได้
เหตุการณ์การนำทางเพื่อหลีกเลี่ยงการเปิดเผยประเภทเส้นทางโดยไม่จำเป็น ดำเนินการโดย
การสร้างฟังก์ชันส่วนขยายใน NavController
// ContactsNavigation.kt
fun NavController.navigateToContactDetails(id: String) {
  navigate(route = ContactDetails(id = id))
}
นำมารวมกัน
รหัสการนำทางสำหรับการแสดงผู้ติดต่อถูกแยกออกจาก ของกราฟการนำทางของแอป โดยแอปต้องมีคุณสมบัติต่อไปนี้
- เรียกใช้ฟังก์ชันของส่วนขยาย NavGraphBuilderเพื่อสร้างปลายทาง
- เชื่อมต่อปลายทางเหล่านั้นโดยเรียกใช้ฟังก์ชันของส่วนขยาย NavControllerสําหรับเหตุการณ์การนําทาง
// MyApp.kt
@Composable
fun MyApp() {
  ...
  NavHost(navController, startDestination = Contacts) {
     contactsDestination(onNavigateToContactDetails = { contactId ->
        navController.navigateToContactDetails(id = contactId)
     })
     contactDetailsDestination()
  }
}
ข้อมูลสรุป
- ห่อหุ้มรหัสการนำทางสำหรับชุดหน้าจอที่เกี่ยวข้องด้วยการวาง ในไฟล์แยกต่างหาก
- แสดงปลายทางด้วยการสร้างฟังก์ชันส่วนขยายใน NavGraphBuilder
- แสดงเหตุการณ์การนำทางด้วยการสร้างฟังก์ชันส่วนขยายใน NavController
- ใช้ internalเพื่อรักษาหน้าจอและประเภทเส้นทางให้เป็นส่วนตัว
