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

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

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

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

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

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

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

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

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

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

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

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

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

@Composable
fun MyApp(
    windowSizeClass: WindowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
) {
    // Perform logic on the size class to decide whether to show the top app bar.
    val showTopAppBar = windowSizeClass.windowHeightSizeClass != WindowHeightSizeClass.COMPACT

    // MyScreen knows nothing about window sizes, and performs logic based on a Boolean flag.
    MyScreen(
        showTopAppBar = showTopAppBar,
        /* ... */
    )
}

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

คอมโพสิเบิลที่ฝังไว้อย่างยืดหยุ่นสามารถนำมาใช้ซ้ำได้

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@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 เสมอ แม้ว่า description จะใช้ก็ต่อเมื่อความกว้างอนุญาตให้แสดงได้ แต่ Card ต้องใช้ description เสมอ ไม่ว่าจะมีความกว้างเท่าใดก็ตาม

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

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

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

วิดีโอ