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

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

หากต้องการรองรับขนาดการแสดงผลให้ได้มากที่สุด ไม่ว่าจะเป็นหน้าจออุปกรณ์ต่างๆ หรือหน้าต่างแอปต่างๆ ในโหมดหลายหน้าต่าง ให้ออกแบบเลย์เอาต์ของแอปให้ตอบสนองและปรับเปลี่ยนได้ เลย์เอาต์ที่ปรับเปลี่ยนตามอุปกรณ์/ปรับตามอุปกรณ์มอบประสบการณ์ของผู้ใช้ที่ปรับให้เหมาะสมโดยไม่คำนึงถึงขนาดการแสดงผล ซึ่งช่วยให้แอปของคุณรองรับโทรศัพท์ แท็บเล็ต อุปกรณ์พับได้ อุปกรณ์ 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 อื่นๆ ได้อย่างชัดเจน เช่นเดียวกับสถานะแอปอื่นๆ การส่งสถานะอย่างชัดเจนจะช่วยลดความซับซ้อนของ Composables แต่ละรายการ เนื่องจาก Composables จะใช้คลาสขนาดหน้าต่างหรือการกำหนดค่าที่ระบุพร้อมกับข้อมูลอื่นๆ

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 โปรดทราบว่าระบบจะส่งdescriptionไปยัง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 เป็นแอปที่ใช้เลย์เอาต์ที่ปรับเปลี่ยนตามอุปกรณ์เพื่อ รองรับขนาดการแสดงผลต่างๆ

วิดีโอ