Navigation Compose API ช่วยให้คุณไปยังส่วนต่างๆ ระหว่าง Composable ในแอป Compose ได้ ขณะเดียวกันก็ใช้ประโยชน์จากคอมโพเนนต์ โครงสร้างพื้นฐาน และฟีเจอร์ของ Jetpack Navigation ได้ด้วย
หน้านี้อธิบายวิธีย้ายข้อมูลจาก Jetpack Navigation ที่อิงตาม Fragment ไปยัง Navigation Compose ซึ่งเป็นส่วนหนึ่งของการย้ายข้อมูล UI ที่อิงตาม View ขนาดใหญ่ไปยัง Jetpack Compose
ข้อกำหนดเบื้องต้นในการย้ายข้อมูล
คุณสามารถย้ายข้อมูลไปยัง Navigation Compose ได้เมื่อแทนที่ Fragment ทั้งหมดด้วย Composable ของหน้าจอที่เกี่ยวข้อง คอมโพสิเบิลของหน้าจอสามารถมีเนื้อหา Compose และ View ผสมกัน แต่ปลายทางการนำทางทั้งหมดต้องเป็นคอมโพสิเบิลเพื่อให้ย้ายข้อมูล Navigation Compose ได้ จนกว่าจะถึงตอนนั้น คุณควรใช้คอมโพเนนต์การนำทางที่อิงตาม Fragment ต่อไปในฐานของโค้ด View และ Compose ที่ทำงานร่วมกันได้ ดูข้อมูลเพิ่มเติมได้ในเอกสารประกอบเกี่ยวกับการทำงานร่วมกันของการนำทาง
ขั้นตอนการย้ายโปรเจ็กต์
ไม่ว่าคุณจะทำตามกลยุทธ์การย้ายข้อมูลที่แนะนำหรือใช้แนวทางอื่น คุณจะไปถึงจุดที่ปลายทางการนำทางทั้งหมดเป็น Composable ของหน้าจอ โดยมี Fragment ทำหน้าที่เป็นคอนเทนเนอร์ Composable เท่านั้น ในขั้นตอนนี้ คุณสามารถย้ายข้อมูลไปยัง Navigation Compose ได้
หากแอปของคุณเป็นไปตามรูปแบบการออกแบบ UDF และคู่มือสถาปัตยกรรมของเราอยู่แล้ว การย้ายข้อมูลไปยัง Jetpack Compose และ Navigation Compose ไม่ควรต้องมีการปรับโครงสร้างโค้ดใหม่ครั้งใหญ่ในเลเยอร์อื่นๆ ของแอป นอกเหนือจากเลเยอร์ UI
หากต้องการย้ายข้อมูลไปยัง Navigation Compose ให้ทำตามขั้นตอนต่อไปนี้
- เพิ่มทรัพยากร Dependency ของ Navigation Compose ลงในแอป
สร้าง Composable
App-levelและเพิ่มลงในActivityเป็นจุดแรกเข้าของ Compose โดยแทนที่การตั้งค่าเลย์เอาต์มุมมองclass SampleActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // setContentView<ActivitySampleBinding>(this, R.layout.activity_sample) setContent { SampleApp(/* ... */) } } }
สร้างประเภทสำหรับปลายทางการนำทางแต่ละรายการ ใช้
data objectสำหรับปลายทางที่ไม่ต้องการข้อมูล และใช้data classหรือclassสำหรับปลายทางที่ต้องการข้อมูล@Serializable data object First @Serializable data class Second(val id: String) @Serializable data object Third
ตั้งค่า
NavControllerในตำแหน่งที่ Composable ทั้งหมดที่ต้องอ้างอิงถึงสามารถเข้าถึงได้ (โดยปกติจะอยู่ภายใน ComposableApp) แนวทางนี้เป็นไปตามหลักการของการย้ายสถานะ และช่วยให้คุณใช้NavControllerเป็นแหล่งข้อมูลที่ถูกต้องเพียงแหล่งเดียวสำหรับการไปยังส่วนต่างๆ ระหว่างหน้าจอ Composable และการรักษา Back Stack ไว้@Composable fun SampleApp() { val navController = rememberNavController() // ... }
สร้าง
NavHostของแอปภายใน ComposableAppและส่งnavController:@Composable fun SampleApp() { val navController = rememberNavController() SampleNavHost(navController = navController) } @Composable fun SampleNavHost( navController: NavHostController ) { NavHost(navController = navController, startDestination = First) { // ... } }
เพิ่มปลายทาง
composableรายการเพื่อสร้างกราฟการนำทาง หากก่อนหน้านี้แต่ละหน้าจอได้รับการย้ายข้อมูลไปยัง Compose แล้ว ขั้นตอนนี้จะประกอบด้วยการดึงข้อมูล Composable ของหน้าจอเหล่านี้จาก Fragment ไปยังปลายทางcomposableเท่านั้นclass FirstFragment : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { return ComposeView(requireContext()).apply { setContent { // FirstScreen(...) EXTRACT FROM HERE } } } } @Composable fun SampleNavHost( navController: NavHostController ) { NavHost(navController = navController, startDestination = First) { composable<First> { FirstScreen(/* ... */) // EXTRACT TO HERE } composable<Second> { SecondScreen(/* ... */) } // ... } }
หากคุณทำตามคำแนะนำเกี่ยวกับการออกแบบสถาปัตยกรรม UI ของ Compose โดยเฉพาะวิธีส่ง
ViewModelและเหตุการณ์การนำทางไปยัง Composable ขั้นตอนถัดไปคือการเปลี่ยนวิธีระบุViewModelให้กับ Composable ของแต่ละหน้าจอ คุณมักจะใช้การแทรก Hilt และจุดผสานรวมกับ Compose และ Navigation ผ่านhiltViewModelได้@Composable fun FirstScreen( // viewModel: FirstViewModel = viewModel(), viewModel: FirstViewModel = hiltViewModel(), onButtonClick: () -> Unit = {}, ) { // ... }
แทนที่การเรียกใช้การนำทาง
findNavController()ทั้งหมดด้วยการเรียกใช้navControllerและส่งการเรียกใช้เหล่านี้เป็นเหตุการณ์การนำทางไปยังหน้าจอ Composable แต่ละหน้าจอ แทนที่จะส่งnavControllerทั้งหมด แนวทางนี้เป็นไปตามแนวทางปฏิบัติแนะนำในการแสดงเหตุการณ์จากฟังก์ชันที่ประกอบกันได้ต่อผู้เรียก และเก็บnavControllerไว้เป็นแหล่งข้อมูลที่เชื่อถือได้เพียงแหล่งเดียว (SSOT)คุณสามารถส่งข้อมูลไปยังปลายทางได้โดยสร้างอินสแตนซ์ของคลาสเส้นทางที่กำหนดไว้สำหรับปลายทางนั้น จากนั้นจะรับผลลัพธ์ได้โดยตรงจากรายการ Back Stack ที่ปลายทางหรือจาก
ViewModelโดยใช้SavedStateHandle.toRoute()@Composable fun SampleNavHost( navController: NavHostController ) { NavHost(navController = navController, startDestination = First) { composable<First> { FirstScreen( onButtonClick = { // findNavController().navigate(firstScreenToSecondScreenAction) navController.navigate(Second(id = "ABC")) } ) } composable<Second> { backStackEntry -> val secondRoute = backStackEntry.toRoute<Second>() SecondScreen( id = secondRoute.id, onIconClick = { // findNavController().navigate(secondScreenToThirdScreenAction) navController.navigate(Third) } ) } // ... } }
นำ Fragment, เลย์เอาต์ XML ที่เกี่ยวข้อง, การนำทางที่ไม่จำเป็นและทรัพยากรอื่นๆ รวมถึงทรัพยากร Dependency ของ Fragment และ Jetpack Navigation ที่ล้าสมัยออกทั้งหมด
คุณดูขั้นตอนเดียวกันพร้อมรายละเอียดเพิ่มเติมที่เกี่ยวข้องกับ Navigation Compose ได้ในเอกสารประกอบการตั้งค่า
กรณีการใช้งานทั่วไป
ไม่ว่าคุณจะใช้คอมโพเนนต์การนำทางใด หลักการนำทางเดียวกันนี้ก็จะมีผลบังคับใช้
กรณีการใช้งานที่พบบ่อยเมื่อย้ายข้อมูลมีดังนี้
- ไปยัง Composable
- ไปยังส่วนต่างๆ ด้วยอาร์กิวเมนต์
- Deep Link
- การนำทางที่ซ้อนกัน
- การผสานรวมกับแถบนำทางด้านล่าง
- การผสานรวมกับคอมโพเนนต์การนำทางที่กำหนดเอง
ดูข้อมูลโดยละเอียดเพิ่มเติมเกี่ยวกับกรณีการใช้งานเหล่านี้ได้ที่การไปยังส่วนต่างๆ ด้วย Compose
ดึงข้อมูลที่ซับซ้อนเมื่อไปยังส่วนต่างๆ
เราขอแนะนำอย่างยิ่งว่าไม่ควรส่งออบเจ็กต์ข้อมูลที่ซับซ้อนไปมาเมื่อไปยังส่วนต่างๆ แต่ให้ส่งข้อมูลที่จำเป็นขั้นต่ำ เช่น ตัวระบุที่ไม่ซ้ำกันหรือรหัสรูปแบบอื่นๆ เป็นอาร์กิวเมนต์เมื่อดำเนินการไปยังส่วนต่างๆ แทน คุณควรจัดเก็บออบเจ็กต์ที่ซับซ้อนเป็นข้อมูลในแหล่งข้อมูลที่เชื่อถือได้เพียงแหล่งเดียว เช่น ชั้นข้อมูล ดูข้อมูลเพิ่มเติมได้ที่การดึงข้อมูลที่ซับซ้อนเมื่อไปยังส่วนต่างๆ
หาก Fragment ส่งออบเจ็กต์ที่ซับซ้อนเป็นอาร์กิวเมนต์ ให้พิจารณาเปลี่ยนโครงสร้างภายในโค้ดก่อน เพื่อให้จัดเก็บและดึงออบเจ็กต์เหล่านี้จากชั้นข้อมูลได้ ดูตัวอย่างได้ที่ที่เก็บ Now in Android
ข้อจำกัด
ส่วนนี้จะอธิบายข้อจำกัดปัจจุบันของ Navigation Compose
การย้ายข้อมูลแบบเพิ่มทีละส่วนไปยัง Navigation Compose
ปัจจุบันคุณไม่สามารถใช้ Navigation Compose ขณะที่ยังใช้ Fragment เป็นปลายทางในโค้ดได้ หากต้องการเริ่มใช้ Navigation Compose ปลายทางทั้งหมดของคุณต้องเป็น Composable คุณติดตามคำขอฟีเจอร์นี้ได้ใน Issue Tracker
ภาพเคลื่อนไหวการเปลี่ยนหน้าต่าง
ตั้งแต่ Navigation 2.7.0-alpha01 เป็นต้นไป การรองรับการตั้งค่าทรานซิชันที่กำหนดเองซึ่งก่อนหน้านี้มาจาก AnimatedNavHost จะได้รับการรองรับโดยตรงใน NavHost อ่านบันทึกประจำรุ่นเพื่อดูข้อมูลเพิ่มเติม
ดูข้อมูลเพิ่มเติม
ดูข้อมูลเพิ่มเติมเกี่ยวกับการย้ายข้อมูลไปยัง Navigation Compose ได้ที่แหล่งข้อมูลต่อไปนี้
- Codelab การนำทางของ Compose: ดูข้อมูลเบื้องต้นเกี่ยวกับการนำทางของ Compose ด้วย Codelab แบบลงมือปฏิบัติจริง
- ที่เก็บ Now in Android: แอป Android ที่ทำงานได้อย่างสมบูรณ์ซึ่งสร้างขึ้นทั้งหมดด้วย Kotlin และ Jetpack Compose โดยเป็นไปตามแนวทางปฏิบัติแนะนำด้านการออกแบบและการพัฒนา Android และมี Navigation Compose
- การย้ายข้อมูล Sunflower ไปยัง Jetpack Compose: บล็อกโพสต์ที่บันทึกเส้นทางการย้ายข้อมูลของแอปตัวอย่าง Sunflower จาก Views ไปยัง Compose ซึ่งรวมถึงการย้ายข้อมูลไปยัง Navigation Compose ด้วย
- Jetnews สำหรับทุกหน้าจอ: บล็อกโพสต์ที่บันทึกการเปลี่ยนโครงสร้างภายในโค้ดและการย้ายข้อมูลตัวอย่าง Jetnews เพื่อรองรับหน้าจอทั้งหมดด้วย Jetpack Compose และ Navigation Compose
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- การนำทางด้วย Compose
- Compose และไลบรารีอื่นๆ
- ปัจจัยอื่นๆ ที่ควรพิจารณา