กราฟแบบฝัง

โดยปกติแล้ว โฟลว์การเข้าสู่ระบบ วิซาร์ด หรือโฟลว์ย่อยอื่นๆ ภายในแอปจะแสดงเป็นกราฟการนำทางที่ซ้อนกันได้ดีที่สุด การซ้อนโฟลว์การนำทางย่อยแบบสแตนด์อโลนในลักษณะนี้จะช่วยให้เข้าใจและจัดการโฟลว์หลักของ UI ของแอปได้ง่ายขึ้น

นอกจากนี้ กราฟแบบฝังยังนำมาใช้ซ้ำได้ด้วย นอกจากนี้ ยังมีการห่อหุ้มในระดับหนึ่งด้วย กล่าวคือ ปลายทางที่อยู่นอกกราฟที่ซ้อนกันจะไม่มีสิทธิ์เข้าถึงปลายทางใดๆ ในกราฟที่ซ้อนกันโดยตรง แต่ควรnavigate()ไปยังกราฟที่ซ้อนกันเอง ซึ่งตรรกะภายในสามารถเปลี่ยนแปลงได้โดยไม่ส่งผลกระทบต่อกราฟที่เหลือ

ตัวอย่าง

กราฟการนำทางระดับบนสุดของแอปควรเริ่มต้นด้วยปลายทางเริ่มต้นที่ผู้ใช้เห็นเมื่อเปิดแอป และควรมีปลายทางที่ผู้ใช้เห็นขณะที่เลื่อนไปมาในแอป

รูปที่ 1 กราฟการนำทางระดับบนสุด

สมมติว่าคุณต้องการกำหนดให้ผู้ใช้เห็นหน้าจอ title_screen และ register เฉพาะเมื่อเปิดแอปเป็นครั้งแรก โดยใช้กราฟการนำทางระดับบนสุดจากรูปที่ 1 เป็นตัวอย่าง หลังจากนั้น ระบบจะจัดเก็บข้อมูลผู้ใช้ และในการเปิดแอปครั้งต่อๆ ไป คุณควรนำผู้ใช้ไปยังหน้าจอการจับคู่โดยตรง

แนวทางปฏิบัติแนะนำคือตั้งค่าหน้าจอการจับคู่เป็นปลายทางเริ่มต้นของ กราฟการนำทางระดับบนสุด และย้ายหน้าจอชื่อและหน้าจอลงทะเบียนไปยังกราฟที่ซ้อนกัน ดังที่แสดงในรูปที่ 1

รูปที่ 2 ตอนนี้กราฟการนำทางระดับบนสุดมีกราฟที่ซ้อนกันอยู่

เมื่อหน้าจอการจับคู่เปิดขึ้น ให้ตรวจสอบว่ามีผู้ใช้ที่ลงทะเบียนหรือไม่ หากผู้ใช้ไม่ได้ลงทะเบียน ให้ไปยังหน้าจอการลงทะเบียน

ดูข้อมูลเพิ่มเติมเกี่ยวกับสถานการณ์การนำทางแบบมีเงื่อนไขได้ที่การนำทางแบบมีเงื่อนไข

เขียน

หากต้องการสร้างกราฟการนำทางที่ซ้อนกันโดยใช้ Compose ให้ใช้ฟังก์ชัน NavGraphBuilder.navigation() คุณใช้ navigation() เหมือนกับฟังก์ชัน NavGraphBuilder.composable() และ NavGraphBuilder.dialog() เมื่อเพิ่มปลายทางลงในกราฟ

ความแตกต่างหลักๆ คือ navigation จะสร้างกราฟที่ซ้อนกันแทนที่จะเป็น ปลายทางใหม่ จากนั้นคุณจะเรียกใช้ composable() และ dialog() ภายใน Lambda ของ navigation() เพื่อเพิ่มปลายทางลงในกราฟที่ซ้อนกัน

พิจารณาว่าข้อมูลโค้ดต่อไปนี้ใช้กราฟในรูปที่ 2 โดยใช้ Compose อย่างไร

// Routes @Serializable object Title @Serializable object Register  // Route for nested graph @Serializable object Game  // Routes inside nested graph @Serializable object Match @Serializable object InGame @Serializable object ResultsWinner @Serializable object GameOver  NavHost(navController, startDestination = Title) {    composable<Title> {        TitleScreen(            onPlayClicked = { navController.navigate(route = Register) },            onLeaderboardsClicked = { /* Navigate to leaderboards */ }        )    }    composable<Register> {        RegisterScreen(            onSignUpComplete = { navController.navigate(route = Game) }        )    }    navigation<Game>(startDestination = Match) {        composable<Match> {            MatchScreen(                onStartGame = { navController.navigate(route = InGame) }            )        }        composable<InGame> {            InGameScreen(                onGameWin = { navController.navigate(route = ResultsWinner) },                onGameLose = { navController.navigate(route = GameOver) }            )        }        composable<ResultsWinner> {            ResultsWinnerScreen(                onNextMatchClicked = {                    navController.navigate(route = Match) {                        popUpTo(route = Match) { inclusive = true }                    }                },                onLeaderboardsClicked = { /* Navigate to leaderboards */ }            )        }        composable<GameOver> {            GameOverScreen(                onTryAgainClicked = {                    navController.navigate(route = Match) {                        popUpTo(route = Match) { inclusive = true }                    }                }            )        }    } } 

หากต้องการไปยังปลายทางที่ซ้อนกันโดยตรง ให้ใช้ประเภทเส้นทางเช่นเดียวกับที่ใช้กับปลายทางอื่นๆ เนื่องจากเส้นทางเป็นแนวคิดระดับโลกที่ใช้เพื่อ ระบุปลายทางที่หน้าจอใดก็ได้ไปยังส่วนต่างๆ

navController.navigate(route = Match) 

XML

เมื่อใช้ XML คุณจะใช้เครื่องมือแก้ไขการนำทางเพื่อสร้างกราฟที่ซ้อนกันได้ โดยทำตามขั้นตอนต่อไปนี้

  1. ในเครื่องมือแก้ไขการนำทาง ให้กดปุ่ม Shift ค้างไว้ แล้วคลิกปลายทางที่ต้องการรวมไว้ในกราฟที่ซ้อนกัน
  2. คลิกขวาเพื่อเปิดเมนูตามบริบท แล้วเลือกย้ายไปยังกราฟที่ซ้อนกัน > กราฟใหม่ โดยปลายทางจะอยู่ในกราฟที่ซ้อนกัน รูปที่ 2 แสดงกราฟที่ซ้อนกันในเครื่องมือแก้ไขการนำทาง

    รูปที่ 2 กราฟแบบฝังในเครื่องมือแก้ไขการนำทาง
  3. คลิกกราฟที่ซ้อนกัน แอตทริบิวต์ต่อไปนี้จะปรากฏในแผงแอตทริบิวต์

    • ประเภทที่มี "กราฟที่ซ้อนกัน"
    • รหัสซึ่งมีรหัสที่ระบบกำหนดสำหรับกราฟที่ซ้อนกัน ระบบจะใช้รหัสนี้เพื่ออ้างอิงกราฟที่ซ้อนกันจากโค้ดของคุณ
  4. ดับเบิลคลิกที่กราฟที่ซ้อนกันเพื่อแสดงปลายทาง

  5. คลิกแท็บข้อความเพื่อสลับไปที่มุมมอง XML เพิ่มกราฟการนำทางที่ซ้อนกัน ลงในกราฟแล้ว กราฟการนำทางนี้มีองค์ประกอบ navigation ของตัวเองพร้อมกับรหัสของตัวเองและแอตทริบิวต์ startDestination ที่ ชี้ไปยังปลายทางแรกในกราฟที่ซ้อนกัน

    <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    xmlns:android="http://schemas.android.com/apk/res/android"    app:startDestination="@id/mainFragment">    <fragment        android:id="@+id/mainFragment"        android:name="com.example.cashdog.cashdog.MainFragment"        android:label="fragment_main"        tools:layout="@layout/fragment_main" >        <action            android:id="@+id/action_mainFragment_to_sendMoneyGraph"            app:destination="@id/sendMoneyGraph" />        <action            android:id="@+id/action_mainFragment_to_viewBalanceFragment"            app:destination="@id/viewBalanceFragment" />    </fragment>    <fragment        android:id="@+id/viewBalanceFragment"        android:name="com.example.cashdog.cashdog.ViewBalanceFragment"        android:label="fragment_view_balance"        tools:layout="@layout/fragment_view_balance" />    <navigation android:id="@+id/sendMoneyGraph" app:startDestination="@id/chooseRecipient">        <fragment            android:id="@+id/chooseRecipient"            android:name="com.example.cashdog.cashdog.ChooseRecipient"            android:label="fragment_choose_recipient"            tools:layout="@layout/fragment_choose_recipient">            <action                android:id="@+id/action_chooseRecipient_to_chooseAmountFragment"                app:destination="@id/chooseAmountFragment" />        </fragment>        <fragment            android:id="@+id/chooseAmountFragment"            android:name="com.example.cashdog.cashdog.ChooseAmountFragment"            android:label="fragment_choose_amount"            tools:layout="@layout/fragment_choose_amount" />    </navigation> </navigation> 
  6. ในโค้ด ให้ส่งรหัสทรัพยากรของการดำเนินการที่เชื่อมต่อกราฟรูท กับกราฟที่ซ้อนกัน

Kotlin

view.findNavController().navigate(R.id.action_mainFragment_to_sendMoneyGraph) 

Java

Navigation.findNavController(view).navigate(R.id.action_mainFragment_to_sendMoneyGraph); 
  1. กลับไปที่แท็บออกแบบ แล้วกลับไปที่กราฟรูทโดยคลิกรูท

อ้างอิงกราฟการนำทางอื่นๆ ด้วย include

อีกวิธีในการแยกโครงสร้างกราฟออกเป็นโมดูลคือการรวมกราฟหนึ่งไว้ภายใน อีกกราฟหนึ่งโดยใช้องค์ประกอบ <include> ในกราฟการนำทางหลัก ซึ่งจะช่วยให้กำหนดกราฟที่รวมไว้ในโมดูลหรือโปรเจ็กต์แยกต่างหากได้ ทั้งหมด ซึ่งจะเพิ่มการนำกลับมาใช้ใหม่ให้ได้มากที่สุด

ข้อมูลโค้ดต่อไปนี้แสดงวิธีใช้ <include>

<!-- (root) nav_graph.xml --> <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:app="http://schemas.android.com/apk/res-auto"     xmlns:tools="http://schemas.android.com/tools"     android:id="@+id/nav_graph"     app:startDestination="@id/fragment">      <include app:graph="@navigation/included_graph" />      <fragment         android:id="@+id/fragment"         android:name="com.example.myapplication.BlankFragment"         android:label="Fragment in Root Graph"         tools:layout="@layout/fragment_blank">         <action             android:id="@+id/action_fragment_to_second_graph"             app:destination="@id/second_graph" />     </fragment>      ... </navigation> 
<!-- included_graph.xml --> <?xml version="1.0" encoding="utf-8"?> <navigation xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:app="http://schemas.android.com/apk/res-auto"     xmlns:tools="http://schemas.android.com/tools"     android:id="@+id/second_graph"     app:startDestination="@id/includedStart">      <fragment         android:id="@+id/includedStart"         android:name="com.example.myapplication.IncludedStart"         android:label="fragment_included_start"         tools:layout="@layout/fragment_included_start" /> </navigation>