รองรับขนาดการแสดงผลที่ต่างกัน

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

หากต้องการรองรับขนาดการแสดงผลให้ได้มากที่สุด ไม่ว่าจะเป็นหน้าจออุปกรณ์ต่างๆ หรือหน้าต่างแอปต่างๆ ในโหมดหลายหน้าต่าง ให้ออกแบบเลย์เอาต์ของแอปให้ตอบสนองและปรับเปลี่ยนได้ เลย์เอาต์ที่ตอบสนองตามอุปกรณ์/ปรับตามอุปกรณ์มอบประสบการณ์การใช้งานที่ ได้รับการเพิ่มประสิทธิภาพโดยไม่คำนึงถึงขนาดการแสดงผล ซึ่งช่วยให้แอปของคุณ รองรับโทรศัพท์ แท็บเล็ต อุปกรณ์พับได้ อุปกรณ์ ChromeOS การวางแนวตั้งและแนวนอน รวมถึงการกำหนดค่าการแสดงผลที่ปรับขนาดได้ เช่น โหมดแยกหน้าจอ และหน้าต่างเดสก์ท็อป

เลย์เอาต์ที่ปรับเปลี่ยนตามพื้นที่โฆษณาจะเปลี่ยนแปลงตามพื้นที่โฆษณาที่มีอยู่ การเปลี่ยนแปลง มีตั้งแต่การปรับเลย์เอาต์เล็กๆ น้อยๆ ที่เติมเต็มพื้นที่ (การออกแบบที่ปรับเปลี่ยนตามพื้นที่โฆษณา) ไปจนถึง การแทนที่เลย์เอาต์หนึ่งด้วยอีกเลย์เอาต์หนึ่งโดยสมบูรณ์ เพื่อให้แอปของคุณรองรับ ขนาดการแสดงผลต่างๆ ได้ดีที่สุด (การออกแบบที่ปรับเปลี่ยนตามอุปกรณ์)

ในฐานะชุดเครื่องมือ UI แบบประกาศสิ่งที่ต้องการ Jetpack Compose จึงเหมาะอย่างยิ่งสำหรับการออกแบบและ การใช้เลย์เอาต์ที่เปลี่ยนแปลงแบบไดนามิกเพื่อแสดงเนื้อหาในรูปแบบต่างๆ บน จอแสดงผลขนาดต่างๆ

ทำการเปลี่ยนแปลงเลย์เอาต์ขนาดใหญ่สำหรับ Composable ระดับเนื้อหาอย่างชัดเจน

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

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

รูปที่ 1 รูปแบบของอุปกรณ์โทรศัพท์ อุปกรณ์แบบพับได้ แท็บเล็ต และแล็ปท็อป

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

แต่ให้ตัดสินใจโดยอิงตามสัดส่วนจริงของหน้าจอที่จัดสรรให้กับแอปของคุณตามที่อธิบายไว้ในเมตริกหน้าต่างปัจจุบันที่ไลบรารี WindowManager ของ Jetpack ระบุ ดูตัวอย่างวิธีใช้ WindowManager ในแอป Compose ได้ที่ตัวอย่าง JetNews

การทําให้เลย์เอาต์ปรับตามพื้นที่แสดงผลที่มีอยู่ได้ยังช่วยลด ปริมาณการจัดการพิเศษที่จําเป็นในการรองรับแพลตฟอร์มอย่าง ChromeOS และ รูปแบบต่างๆ เช่น แท็บเล็ตและอุปกรณ์พับได้

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

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

@Composable
fun MyApp(
    windowSizeClass: WindowSizeClass = currentWindowAdaptiveInfo(supportLargeAndXLargeWidth = true).windowSizeClass
) {
    // Decide whether to show the top app bar based on window size class.
    val showTopAppBar = windowSizeClass.isHeightAtLeastBreakpoint(WindowSizeClass.HEIGHT_DP_MEDIUM_LOWER_BOUND)

    // MyScreen logic is based on the showTopAppBar boolean flag.
    MyScreen(
        showTopAppBar = showTopAppBar,
        /* ... */
    )
}

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

Composable แบบซ้อนกันที่ยืดหยุ่นจะใช้ซ้ำได้

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

ลองนึกถึง Composable แบบซ้อนที่ใช้เลย์เอาต์แบบรายการ-รายละเอียด ซึ่งอาจแสดงบานหน้าต่างเดียวหรือ 2 บานหน้าต่างข้างกันก็ได้

แอปที่แสดง 2 บานหน้าต่างเคียงข้างกัน
รูปที่ 2 แอปที่แสดงเลย์เอาต์รายละเอียดรายการทั่วไป - 1 คือพื้นที่รายการ ส่วน 2 คือพื้นที่รายละเอียด

การตัดสินใจเกี่ยวกับรายละเอียดรายการควรเป็นส่วนหนึ่งของเลย์เอาต์โดยรวมของแอป ดังนั้น การตัดสินใจจึงส่งต่อจาก Composable ระดับเนื้อหา

@Composable
fun AdaptivePane(
    showOnePane: Boolean,
    /* ... */
) {
    if (showOnePane) {
        OnePane(/* ... */)
    } else {
        TwoPane(/* ... */)
    }
}

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

รูปที่ 3 การ์ดแบบแคบที่แสดงเฉพาะไอคอนและชื่อ และการ์ดแบบกว้างที่แสดงไอคอน ชื่อ และคำอธิบายสั้นๆ

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

เนื่องจาก Composable ไม่ใช่ Composable ระดับเนื้อหา จึงไม่ควรใช้เมตริกหน้าต่างปัจจุบันโดยตรง

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

ใช้ความกว้างที่ Composable ได้รับจริงเพื่อแสดงผล คุณมี 2 ตัวเลือกในการรับความกว้างดังกล่าว

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

  • หากต้องการเปลี่ยนสิ่งที่แสดง ให้ใช้ BoxWithConstraints เป็นทางเลือกที่มีประสิทธิภาพมากกว่า BoxWithConstraints มีข้อจำกัดด้านการวัดผลที่คุณใช้เรียก Composable ต่างๆ ได้ตาม พื้นที่แสดงผลที่ใช้ได้ อย่างไรก็ตาม การทำเช่นนี้มีค่าใช้จ่ายบางอย่าง เนื่องจาก BoxWithConstraints จะเลื่อนการจัดองค์ประกอบไปจนถึงระยะเลย์เอาต์เมื่อทราบข้อจำกัดเหล่านี้แล้ว ซึ่งทำให้ต้องทำงานมากขึ้นในระหว่างเลย์เอาต์

@Composable
fun Card(/* ... */) {
    BoxWithConstraints {
        if (maxWidth < 400.dp) {
            Column {
                Image(/* ... */)
                Title(/* ... */)
            }
        } else {
            Row {
                Column {
                    Title(/* ... */)
                    Description(/* ... */)
                }
                Image(/* ... */)
            }
        }
    }
}

ทำให้ข้อมูลทั้งหมดพร้อมใช้งานสำหรับขนาดการแสดงผลต่างๆ

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

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

@Composable
fun Card(
    imageUrl: String,
    title: String,
    description: String
) {
    BoxWithConstraints {
        if (maxWidth < 400.dp) {
            Column {
                Image(imageUrl)
                Title(title)
            }
        } else {
            Row {
                Column {
                    Title(title)
                    Description(description)
                }
                Image(imageUrl)
            }
        }
    }
}

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

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

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

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

@Composable
fun Card(
    imageUrl: String,
    title: String,
    description: String
) {
    var showMore by remember { mutableStateOf(false) }

    BoxWithConstraints {
        if (maxWidth < 400.dp) {
            Column {
                Image(imageUrl)
                Title(title)
            }
        } else {
            Row {
                Column {
                    Title(title)
                    Description(
                        description = description,
                        showMore = showMore,
                        onShowMoreToggled = { newValue ->
                            showMore = newValue
                        }
                    )
                }
                Image(imageUrl)
            }
        }
    }
}

ดูข้อมูลเพิ่มเติม

ดูข้อมูลเพิ่มเติมเกี่ยวกับเลย์เอาต์ที่ปรับเปลี่ยนได้ใน Compose ได้ที่แหล่งข้อมูลต่อไปนี้

แอปตัวอย่าง

  • CanonicalLayouts คือที่เก็บรูปแบบการออกแบบที่ได้รับการพิสูจน์แล้ว ซึ่งมอบประสบการณ์การใช้งานที่เหมาะสมที่สุดบนจอแสดงผลขนาดใหญ่
  • JetNews แสดงวิธีออกแบบแอปที่ปรับ UI ให้ใช้พื้นที่แสดงผลที่มีอยู่
  • Reply เป็นตัวอย่างที่ปรับเปลี่ยนได้สำหรับการรองรับมือถือ แท็บเล็ต และอุปกรณ์พับได้
  • Now in Android เป็นแอปที่ใช้เลย์เอาต์ที่ปรับเปลี่ยนอัตโนมัติเพื่อ รองรับขนาดการแสดงผลต่างๆ

วิดีโอ