สร้างเลย์เอาต์รายละเอียดรายการ

รายละเอียดรายการ เป็นรูปแบบ UI ที่ประกอบด้วยการแยกหน้าจอ โดยแผงหนึ่งจะแสดงรายการ และอีกแผงจะแสดงรายละเอียดของรายการที่เลือกจากรายการ

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

บานหน้าต่างรายละเอียดที่แสดงข้างหน้าเพจรายการ
รูปที่ 1 เมื่อมีขนาดหน้าจอเพียงพอ ระบบจะแสดงบานหน้าต่างรายละเอียด ควบคู่ไปกับบานหน้าต่างรายการ
หลังจากเลือกรายการแล้ว บานหน้าต่างรายละเอียดจะครอบครองทั้งหน้าจอ
รูปที่ 2 เมื่อขนาดหน้าจอมีจำกัด บานหน้าต่างรายละเอียด (เนื่องจากมีการเลือกรายการ) จะใช้พื้นที่ทั้งหมด

ใช้รูปแบบ List-Detail ด้วย NavigableListDetailPaneScaffold

NavigableListDetailPaneScaffold เป็น Composable ที่ช่วยให้การใช้เลย์เอาต์รายละเอียดรายการใน Jetpack Compose ง่ายขึ้น โดยจะรวม ListDetailPaneScaffold และเพิ่มการนำทางในตัว รวมถึงภาพเคลื่อนไหวของการย้อนกลับที่คาดการณ์ได้

Scaffold แบบรายละเอียดรายการ รองรับบานหน้าต่างได้สูงสุด 3 บาน ดังนี้

  1. บานหน้าต่างรายการ: แสดงคอลเล็กชันรายการ
  2. บานหน้าต่างรายละเอียด: แสดงรายละเอียดของรายการที่เลือก
  3. บานหน้าต่างเพิ่มเติม (ไม่บังคับ): ให้บริบทเพิ่มเติมเมื่อจำเป็น

Scaffold จะปรับตามขนาดหน้าต่าง ดังนี้

  • ในหน้าต่างขนาดใหญ่ บานหน้าต่างรายการและรายละเอียดจะปรากฏเคียงข้างกัน
  • ในหน้าต่างขนาดเล็ก จะมีเพียงบานหน้าต่างเดียวที่ปรากฏขึ้นในแต่ละครั้ง โดยจะสลับไปมาเมื่อผู้ใช้ไปยังส่วนต่างๆ

ประกาศทรัพยากร Dependency

NavigableListDetailPaneScaffold เป็นส่วนหนึ่งของ ไลบรารี การนำทางแบบปรับเปลี่ยนได้ของ Material 3

เพิ่มทรัพยากร Dependency ที่เกี่ยวข้อง 3 รายการต่อไปนี้ลงในไฟล์ build.gradle ของแอปหรือโมดูล

Kotlin

implementation("androidx.compose.material3.adaptive:adaptive")
implementation("androidx.compose.material3.adaptive:adaptive-layout")
implementation("androidx.compose.material3.adaptive:adaptive-navigation")

ดึงดูด

implementation 'androidx.compose.material3.adaptive:adaptive'
implementation 'androidx.compose.material3.adaptive:adaptive-layout'
implementation 'androidx.compose.material3.adaptive:adaptive-navigation'
  • adaptive: องค์ประกอบระดับต่ำ เช่น HingeInfo และ Posture
  • adaptive-layout: เลย์เอาต์แบบปรับเปลี่ยนได้ เช่น ListDetailPaneScaffold และ SupportingPaneScaffold
  • adaptive-navigation: Composables สำหรับการนำทางภายในและระหว่างบานหน้าต่าง รวมถึงเลย์เอาต์แบบปรับเปลี่ยนได้ที่รองรับการนำทางโดยค่าเริ่มต้น เช่น NavigableListDetailPaneScaffold และ NavigableSupportingPaneScaffold

ตรวจสอบว่าโปรเจ็กต์มี compose-material3-adaptive เวอร์ชัน 1.1.0-beta1 ขึ้นไป

เลือกใช้ท่าทางสัมผัสการย้อนกลับที่คาดการณ์ได้

หากต้องการเปิดใช้ภาพเคลื่อนไหวของการย้อนกลับที่คาดการณ์ได้ใน Android 15 หรือต่ำกว่า คุณต้องเลือกใช้เพื่อรองรับท่าทางสัมผัสการย้อนกลับที่คาดการณ์ได้ หากต้องการเลือกใช้ ให้เพิ่ม android:enableOnBackInvokedCallback="true" ลงในแท็ก <application> หรือ แท็ก <activity> แต่ละรายการภายในไฟล์ AndroidManifest.xml ดูข้อมูลเพิ่มเติมได้ที่ เลือกใช้ท่าทางสัมผัสการย้อนกลับที่คาดการณ์ได้

เมื่อแอปกำหนดเป้าหมายเป็น Android 16 (ระดับ API 36) ขึ้นไป ระบบจะเปิดใช้การย้อนกลับที่คาดการณ์ได้โดยค่าเริ่มต้น

การใช้งานพื้นฐาน

ใช้ NavigableListDetailPaneScaffold ดังนี้

  1. ใช้คลาสที่แสดงเนื้อหาที่เลือก ใช้คลาส Parcelable เพื่อรองรับการบันทึกและกู้คืนรายการที่เลือก ใช้ ปลั๊กอิน kotlin-parcelize เพื่อสร้างโค้ดให้คุณ
  2. สร้าง ThreePaneScaffoldNavigator ด้วย rememberListDetailPaneScaffoldNavigator

โดยใช้ Navigator นี้เพื่อย้ายไปมาระหว่างบานหน้าต่างรายการ รายละเอียด และเพิ่มเติม เมื่อประกาศประเภททั่วไป Navigator จะติดตามสถานะของ Scaffold ด้วย (เช่น MyItem ใดที่กำลังแสดงอยู่) เนื่องจากประเภทนี้เป็น Parcelable Navigator จึงบันทึกและกู้คืนสถานะได้เพื่อจัดการการเปลี่ยนแปลงการกำหนดค่าโดยอัตโนมัติ

  1. ส่ง Navigator ไปยัง Composable NavigableListDetailPaneScaffold

  2. ระบุการใช้งานบานหน้าต่างรายการให้กับ NavigableListDetailPaneScaffold ใช้ AnimatedPane เพื่อใช้ ภาพเคลื่อนไหวของบานหน้าต่างเริ่มต้นระหว่างการนำทาง จากนั้นใช้ ThreePaneScaffoldNavigator เพื่อไปยังบานหน้าต่างรายละเอียด ListDetailPaneScaffoldRole.Detail และแสดงรายการที่ส่ง

  3. รวมการใช้งานบานหน้าต่างรายละเอียดไว้ใน NavigableListDetailPaneScaffold

เมื่อการนำทางเสร็จสมบูรณ์ currentDestination จะมีบานหน้าต่างที่แอปไปยังส่วนนั้น รวมถึงเนื้อหาที่แสดงในบานหน้าต่าง พร็อพเพอร์ตี้ contentKey เป็นประเภทเดียวกับที่ระบุไว้ในการเรียกเดิม คุณจึงเข้าถึงข้อมูลที่ต้องการแสดงได้

  1. เลือกเปลี่ยน defaultBackBehavior ใน NavigableListDetailPaneScaffold โดยค่าเริ่มต้น NavigableListDetailPaneScaffold จะใช้ PopUntilScaffoldValueChange สำหรับ defaultBackBehavior

หากแอปต้องใช้รูปแบบการนำทางย้อนกลับที่แตกต่างออกไป คุณสามารถลบล้างลักษณะการทำงานนี้ได้โดยการระบุตัวเลือก BackNavigationBehavior อื่น

ตัวเลือก BackNavigationBehavior

ส่วนต่อไปนี้จะใช้ตัวอย่างแอปอีเมลที่มีรายการอีเมลในบานหน้าต่างหนึ่งและมุมมองโดยละเอียดในอีกบานหน้าต่างหนึ่ง

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

ลองดูตัวอย่างต่อไปนี้

  • หลายบานหน้าต่าง: คุณกำลังดูอีเมล (รายการที่ 1) ในบานหน้าต่างรายละเอียด การคลิกอีเมลอื่น (รายการที่ 2) จะอัปเดตบานหน้าต่างรายละเอียด แต่บานหน้าต่างรายการและรายละเอียดจะยังคงปรากฏอยู่ การกดปุ่มย้อนกลับอาจออกจากแอปหรือขั้นตอนการนำทางปัจจุบัน
  • บานหน้าต่างเดียว: คุณดูรายการที่ 1 แล้วดูรายการที่ 2 การกดปุ่มย้อนกลับจะนำคุณกลับไปที่บานหน้าต่างรายชื่ออีเมลโดยตรง

ใช้ตัวเลือกนี้เมื่อต้องการให้ผู้ใช้รับรู้ถึงการเปลี่ยนเลย์เอาต์ที่แตกต่างกันในแต่ละการดำเนินการย้อนกลับ

การเปลี่ยนแปลงค่าการนำทาง
PopUntilContentChange

ลักษณะการทำงานนี้จะจัดลำดับความสำคัญของเนื้อหาที่แสดง หากคุณดูรายการที่ 1 แล้วดูรายการที่ 2 การกดปุ่มย้อนกลับจะเปลี่ยนกลับไปที่รายการที่ 1 ไม่ว่าเลย์เอาต์จะเป็นอย่างไร

ลองดูตัวอย่างต่อไปนี้

  • หลายบานหน้าต่าง: คุณดูรายการที่ 1 ในบานหน้าต่างรายละเอียด แล้วคลิกรายการที่ 2 ในรายการ บานหน้าต่างรายละเอียดจะอัปเดต การกดปุ่มย้อนกลับจะกู้คืนบานหน้าต่างรายละเอียดเป็นรายการที่ 1
  • บานหน้าต่างเดียว: การเปลี่ยนกลับเนื้อหาแบบเดียวกันจะเกิดขึ้น

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

การเปลี่ยนระหว่างแผงรายละเอียด 2 แผง
PopUntilCurrentDestinationChange

ลักษณะการทำงานนี้จะนำรายการออกจาก Back Stack จนกว่า ปลายทางการนำทางปัจจุบัน จะเปลี่ยนไป ซึ่งจะมีผลกับเลย์เอาต์บานหน้าต่างเดียวและหลายบานหน้าต่างเท่ากัน

ลองดูตัวอย่างต่อไปนี้

ไม่ว่าคุณจะอยู่ในเลย์เอาต์บานหน้าต่างเดียวหรือหลายบานหน้าต่าง การกดปุ่มย้อนกลับจะย้ายโฟกัสจากองค์ประกอบการนำทางที่ไฮไลต์ไปยังปลายทางก่อนหน้าเสมอ ในแอปอีเมลของเรา หมายความว่าการแสดงภาพของบานหน้าต่างที่เลือกจะเปลี่ยนไป

ใช้ตัวเลือกนี้เมื่อการรักษาการแสดงภาพที่ชัดเจนของการนำทางปัจจุบันมีความสำคัญต่อประสบการณ์ของผู้ใช้

การไปยังส่วนต่างๆ ระหว่างแผงรายละเอียดและแผงรายการ
PopLatest

ตัวเลือกนี้จะนำเฉพาะปลายทางล่าสุดออกจากสแต็กย้อนกลับ ใช้ตัวเลือกนี้สำหรับการนำทางย้อนกลับโดยไม่ข้ามสถานะกลาง

หลังจากทำตามขั้นตอนเหล่านี้แล้ว โค้ดของคุณควรมีลักษณะคล้ายกับโค้ดต่อไปนี้

NavigableListDetailPaneScaffold(
    navigator = navigator,
    listPane = {
        AnimatedPane {
            ListContent(
                words = sampleWords,
                selectionState = navigator.currentDestination?.contentKey?.let {
                    SelectionVisibilityState.ShowSelection(it)
                } ?: SelectionVisibilityState.NoSelection,
                onWordClick = { word ->
                    scope.launch {
                        navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, word)
                    }
                },
                animatedVisibilityScope = this@AnimatedPane,
                sharedTransitionScope = this@SharedTransitionLayout
            )
        }
    },
    detailPane = {
        AnimatedPane {
            DetailContent(
                definedWord = navigator.currentDestination?.contentKey,
                animatedVisibilityScope = this@AnimatedPane,
                sharedTransitionScope = this@SharedTransitionLayout,
                onClosePane = {
                    scope.launch {
                        navigator.navigateBack(
                            backNavigationBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange
                        )

                    }
                }
            )
        }
    }