ห่อหุ้มรหัสการนำทาง

เมื่อใช้ 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 เพื่อรักษาหน้าจอและประเภทเส้นทางให้เป็นส่วนตัว