สร้างเลย์เอาต์แผงรองรับ

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

ดูรายละเอียดเพิ่มเติมได้ที่หลักเกณฑ์เกี่ยวกับแผงรองรับ Material 3

ใช้แผงสนับสนุนกับโครงร่าง

NavigableSupportingPaneScaffold เป็นฟังก์ชันที่ประกอบกันได้ซึ่งช่วยลดความซับซ้อนในการ ใช้เลย์เอาต์แผงด้านข้างใน Jetpack Compose โดยจะรวม SupportingPaneScaffold และเพิ่มการนำทางในตัวและการจัดการการย้อนกลับแบบคาดการณ์

โครงสร้างบานหน้าต่างรองรับบานหน้าต่างได้สูงสุด 3 บาน ดังนี้

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

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

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

    เนื้อหาหลักที่ใช้พื้นที่ส่วนใหญ่ของจอแสดงผลโดยมีเนื้อหาสนับสนุนอยู่ข้างๆ
    รูปที่ 1 เลย์เอาต์ของแผงสนับสนุน

เพิ่มทรัพยากร Dependency

NavigableSupportingPaneScaffold เป็นส่วนหนึ่งของไลบรารีเลย์เอาต์แบบปรับได้ของ 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")

Groovy

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: Composable สำหรับการไปยังส่วนต่างๆ ภายในและระหว่าง บานหน้าต่าง รวมถึงเลย์เอาต์แบบปรับได้ที่รองรับการนำทางโดยค่าเริ่มต้น เช่น NavigableListDetailPaneScaffold และ NavigableSupportingPaneScaffold

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

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

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

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

สร้างตัวนำทาง

ในหน้าต่างขนาดเล็ก จะมีเพียง 1 บานหน้าต่างที่แสดงในแต่ละครั้ง ดังนั้นให้ใช้ ThreePaneScaffoldNavigatorเพื่อไปยังบานหน้าต่างต่างๆ สร้างอินสแตนซ์ ของ Navigator ด้วย rememberSupportingPaneScaffoldNavigator

val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator()
val scope = rememberCoroutineScope()

ส่ง Navigator ไปยัง Scaffold

โครงสร้างต้องมี ThreePaneScaffoldNavigator ซึ่งเป็นอินเทอร์เฟซ ที่แสดงสถานะของโครงสร้าง ThreePaneScaffoldValue และ PaneScaffoldDirective

NavigableSupportingPaneScaffold(
    navigator = scaffoldNavigator,
    mainPane = { /*...*/ },
    supportingPane = { /*...*/ },
)

บานหน้าต่างหลักและบานหน้าต่างสนับสนุนเป็น Composable ที่มีเนื้อหาของคุณ ใช้ AnimatedPaneเพื่อใช้ภาพเคลื่อนไหวของแผงเริ่มต้นระหว่างการนำทาง ใช้ค่าโครงสร้างเพื่อตรวจสอบว่าซ่อนแผงสนับสนุนหรือไม่ หากซ่อน ให้แสดงปุ่มที่เรียก navigateTo(SupportingPaneScaffoldRole.Supporting) เพื่อแสดงแผงสนับสนุน

การใช้งานโครงร่างที่สมบูรณ์มีดังนี้

val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator()
val scope = rememberCoroutineScope()

NavigableSupportingPaneScaffold(
    navigator = scaffoldNavigator,
    mainPane = {
        AnimatedPane(
            modifier = Modifier
                .safeContentPadding()
                .background(Color.Red)
        ) {
            if (scaffoldNavigator.scaffoldValue[SupportingPaneScaffoldRole.Supporting] == PaneAdaptedValue.Hidden) {
                Button(
                    modifier = Modifier
                        .wrapContentSize(),
                    onClick = {
                        scope.launch {
                            scaffoldNavigator.navigateTo(SupportingPaneScaffoldRole.Supporting)
                        }
                    }
                ) {
                    Text("Show supporting pane")
                }
            } else {
                Text("Supporting pane is shown")
            }
        }
    },
    supportingPane = {
        AnimatedPane(modifier = Modifier.safeContentPadding()) {
            Text("Supporting pane")
        }
    }
)

คอมโพเนนต์ของแผงการแยก

แยกแต่ละบานหน้าต่างของ SupportingPaneScaffold ออกเป็น Composable ของตัวเองเพื่อให้สามารถนำกลับมาใช้ใหม่และทดสอบได้ ใช้ ThreePaneScaffoldScope เพื่อเข้าถึง AnimatedPane หากต้องการใช้ภาพเคลื่อนไหวเริ่มต้น

@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
fun ThreePaneScaffoldPaneScope.MainPane(
    shouldShowSupportingPaneButton: Boolean,
    onNavigateToSupportingPane: () -> Unit,
    modifier: Modifier = Modifier,
) {
    AnimatedPane(
        modifier = modifier.safeContentPadding()
    ) {
        // Main pane content
        if (shouldShowSupportingPaneButton) {
            Button(onClick = onNavigateToSupportingPane) {
                Text("Show supporting pane")
            }
        } else {
            Text("Supporting pane is shown")
        }
    }
}

@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
fun ThreePaneScaffoldPaneScope.SupportingPane(
    modifier: Modifier = Modifier,
) {
    AnimatedPane(modifier = modifier.safeContentPadding()) {
        // Supporting pane content
        Text("This is the supporting pane")
    }
}

การแยกบานหน้าต่างออกเป็น Composable จะช่วยให้ใช้งาน SupportingPaneScaffold ได้ง่ายขึ้น (เปรียบเทียบสิ่งต่อไปนี้กับการใช้งาน Scaffold ที่สมบูรณ์ ในส่วนก่อนหน้า)

val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator()
val scope = rememberCoroutineScope()

NavigableSupportingPaneScaffold(
    navigator = scaffoldNavigator,
    mainPane = {
        MainPane(
            shouldShowSupportingPaneButton = scaffoldNavigator.scaffoldValue.secondary == PaneAdaptedValue.Hidden,
            onNavigateToSupportingPane = {
                scope.launch {
                    scaffoldNavigator.navigateTo(ThreePaneScaffoldRole.Secondary)
                }
            }
        )
    },
    supportingPane = { SupportingPane() },
)

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

เพิ่ม ThreePaneScaffoldPredictiveBackHandler

แนบตัวแฮนเดิลท่าทางสัมผัสย้อนกลับแบบคาดเดาซึ่งใช้อินสแตนซ์ของ Scaffold Navigator และระบุ backBehavior ซึ่งจะเป็นตัวกำหนดวิธีที่ระบบจะนำปลายทางออกจาก Backstack ระหว่างการไปยังส่วนก่อนหน้า จากนั้นส่ง scaffoldDirective และ scaffoldState ไปยัง SupportingPaneScaffold ใช้การโอเวอร์โหลดที่ยอมรับ a ThreePaneScaffoldState โดยส่งใน scaffoldNavigator.scaffoldState

กำหนดบานหน้าต่างหลักและบานหน้าต่างสนับสนุนภายใน SupportingPaneScaffold ใช้ AnimatedPane สำหรับภาพเคลื่อนไหวของบานหน้าต่างเริ่มต้น

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

val scaffoldNavigator = rememberSupportingPaneScaffoldNavigator()
val scope = rememberCoroutineScope()

ThreePaneScaffoldPredictiveBackHandler(
    navigator = scaffoldNavigator,
    backBehavior = BackNavigationBehavior.PopUntilScaffoldValueChange
)

SupportingPaneScaffold(
    directive = scaffoldNavigator.scaffoldDirective,
    scaffoldState = scaffoldNavigator.scaffoldState,
    mainPane = {
        MainPane(
            shouldShowSupportingPaneButton = scaffoldNavigator.scaffoldValue.secondary == PaneAdaptedValue.Hidden,
            onNavigateToSupportingPane = {
                scope.launch {
                    scaffoldNavigator.navigateTo(ThreePaneScaffoldRole.Secondary)
                }
            }
        )
    },
    supportingPane = { SupportingPane() },
)