การรองรับหน้าจอขนาดต่างๆ ช่วยให้ผู้ใช้จำนวนมากและอุปกรณ์ที่หลากหลายเข้าถึงแอปของคุณได้
ออกแบบเลย์เอาต์แอปให้ปรับเปลี่ยนตามอุปกรณ์และรองรับหน้าจอหลายขนาดมากที่สุด เลย์เอาต์ที่ตอบสนอง/ปรับเปลี่ยนได้มอบประสบการณ์การใช้งานที่เพิ่มประสิทธิภาพให้ผู้ใช้โดยไม่คำนึงถึงขนาดหน้าจอ ซึ่งช่วยให้แอปของคุณรองรับโทรศัพท์ แท็บเล็ต อุปกรณ์แบบพับได้ อุปกรณ์ ChromeOS การวางแนวแนวตั้งและแนวนอน ตลอดจนการกำหนดค่าที่ปรับขนาดได้ เช่น โหมดหลายหน้าต่าง
เลย์เอาต์ที่ปรับเปลี่ยนตามพื้นที่โฆษณา/ที่ปรับเปลี่ยนจะเปลี่ยนแปลงตามพื้นที่โฆษณาที่มีอยู่ การเปลี่ยนแปลงมีตั้งแต่การปรับเลย์เอาต์เล็กน้อยเพื่อใช้พื้นที่ว่างให้เกิดประโยชน์สูงสุด (การออกแบบที่ปรับเปลี่ยนตามพื้นที่โฆษณา) ไปจนถึงการเปลี่ยนเลย์เอาต์หนึ่งด้วยอีกเลย์เอาต์หนึ่งโดยสมบูรณ์เพื่อให้แอปรองรับขนาดการแสดงผลที่แตกต่างกันได้ดีที่สุด (การออกแบบที่ปรับเปลี่ยนได้)
ในฐานะชุดเครื่องมือ UI แบบประกาศสิ่งที่ต้องการ Jetpack Compose เหมาะสําหรับการออกแบบและการใช้เลย์เอาต์ที่เปลี่ยนแปลงแบบไดนามิกเพื่อแสดงผลเนื้อหาในลักษณะที่แตกต่างกันในหน้าจอขนาดต่างๆ
ทำการเปลี่ยนแปลงเลย์เอาต์ขนาดใหญ่สำหรับคอมโพสิเบิลระดับหน้าจออย่างชัดเจน
เมื่อใช้ Compose เพื่อวางเลย์เอาต์แอปพลิเคชันทั้งหมด คอมโพสิเบิลระดับแอปและระดับหน้าจอจะใช้พื้นที่ทั้งหมดที่แอปได้รับเพื่อแสดงผล เมื่อออกแบบในระดับนี้ คุณอาจต้องเปลี่ยนเลย์เอาต์โดยรวมของหน้าจอเพื่อใช้ประโยชน์จากหน้าจอขนาดใหญ่
หลีกเลี่ยงการใช้ค่าฮาร์ดแวร์จริงในการตัดสินใจเกี่ยวกับเลย์เอาต์ คุณอาจอยากตัดสินใจตามมูลค่าที่จับต้องได้แบบคงที่ (อุปกรณ์เป็นแท็บเล็ตไหม หน้าจอจริงมีส่วนสัดส่วนภาพแบบใด) แต่คําตอบของคําถามเหล่านี้อาจไม่เป็นประโยชน์ในการกําหนดพื้นที่ที่ UI ของคุณใช้งานได้
ในแท็บเล็ต แอปอาจทำงานในโหมดหลายหน้าต่าง ซึ่งหมายความว่าแอปอาจแยกหน้าจอกับแอปอื่นอยู่ ใน 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, /* ... */ ) }
แนวทางแบบเป็นชั้นนี้จะจำกัดตรรกะขนาดหน้าจอไว้ที่ตำแหน่งเดียว แทนที่จะกระจายตรรกะดังกล่าวไปทั่วแอปในหลายๆ ตําแหน่งที่ต้องซิงค์กัน ตำแหน่งเดียวนี้จะสร้างสถานะ ซึ่งสามารถส่งต่อไปยังคอมโพสิเบิลอื่นๆ ได้อย่างชัดเจน เช่นเดียวกับที่คุณทำกับสถานะแอปอื่นๆ การระบุสถานะอย่างชัดเจนจะลดความซับซ้อนของคอมโพสิเบิลแต่ละรายการ เนื่องจากจะเป็นฟังก์ชันคอมโพสิเบิลปกติที่ใช้คลาสขนาดหรือการกําหนดค่าที่ระบุพร้อมกับข้อมูลอื่นๆ
คอมโพสิเบิลที่ฝังไว้อย่างยืดหยุ่นสามารถนำมาใช้ซ้ำได้
คอมโพสิเบิลจะนํากลับมาใช้ซ้ำได้มากขึ้นเมื่อวางได้หลายตําแหน่ง หากคอมโพสิเบิลถือว่าจะมีการจัดวางในตำแหน่งที่เจาะจงซึ่งมีขนาดที่เฉพาะเจาะจงเสมอ การนำไปใช้ซ้ำในที่อื่นในตำแหน่งอื่นหรือที่มีพื้นที่ว่างแตกต่างกันก็จะทำได้ยากขึ้น ซึ่งหมายความว่าคอมโพสิเบิลแบบใช้ซ้ำได้แต่ละรายการควรหลีกเลี่ยงการพึ่งพาข้อมูลขนาด "ส่วนกลาง" โดยนัย
พิจารณาตัวอย่างต่อไปนี้ ลองจินตนาการถึงคอมโพสิเบิลที่ฝังอยู่ซึ่งใช้เลย์เอาต์รายการแบบละเอียด ซึ่งอาจแสดงแผง 1 หรือ 2 แผงเคียงข้างกัน
เราต้องการให้การตัดสินใจนี้เป็นส่วนหนึ่งของเลย์เอาต์โดยรวมของแอป เราจึงส่งต่อการตัดสินใจจากคอมโพสิเบิลระดับหน้าจอดังที่เราเห็นด้านบน
@Composable fun AdaptivePane( showOnePane: Boolean, /* ... */ ) { if (showOnePane) { OnePane(/* ... */) } else { TwoPane(/* ... */) } }
จะเกิดอะไรขึ้นหากเราต้องการให้คอมโพสิเบิลเปลี่ยนเลย์เอาต์อย่างอิสระตามพื้นที่ว่างที่มีอยู่แทน เช่น การ์ดที่ต้องการแสดงรายละเอียดเพิ่มเติมหากมีพื้นที่เพียงพอ เราต้องการดำเนินการตามตรรกะบางอย่างตามขนาดที่มี แต่ ขนาดใดกันแน่
ดังที่เราเห็นด้านบน เราควรหลีกเลี่ยงการใช้ขนาดหน้าจอจริงของอุปกรณ์ ข้อมูลนี้จะไม่ถูกต้องสำหรับหน้าจอหลายหน้าจอ และจะไม่ถูกต้องหากแอปไม่ได้แสดงแบบเต็มหน้าจอ
เนื่องจากคอมโพสิเบิลไม่ใช่คอมโพสิเบิลระดับหน้าจอ เราจึงไม่ควรใช้เมตริกกรอบเวลาปัจจุบันโดยตรงเพื่อเพิ่มความสามารถในการนํากลับมาใช้ซ้ำให้ได้สูงสุด หากวางคอมโพเนนต์โดยมีการเว้นวรรค (เช่น สำหรับการฝัง) หรือหากมีคอมโพเนนต์ เช่น แถบนำทางหรือแถบแอป พื้นที่ที่ใช้ได้สำหรับคอมโพสิเบิลอาจแตกต่างจากพื้นที่โดยรวมที่ใช้ได้สำหรับแอปอย่างมาก
ดังนั้น เราควรใช้ความกว้างที่คอมโพสิเบิลได้รับจริงเพื่อแสดงผล เรามี 2 วิธีในการรับค่าความกว้างนั้น
หากต้องการเปลี่ยนตําแหน่งหรือวิธีแสดงเนื้อหา ให้ใช้ชุดตัวแก้ไขหรือเลย์เอาต์ที่กําหนดเองเพื่อทําให้เลย์เอาต์ปรับเปลี่ยนได้ ซึ่งอาจทำได้ง่ายๆ เพียงให้องค์ประกอบบางส่วนเติมเต็มพื้นที่ว่างทั้งหมด หรือจัดวางองค์ประกอบด้วยหลายคอลัมน์หากมีพื้นที่เพียงพอ
หากต้องการเปลี่ยนสิ่งที่แสดง คุณสามารถใช้ 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
Boolean 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) } } } }
ดูข้อมูลเพิ่มเติม
ดูข้อมูลเพิ่มเติมเกี่ยวกับเลย์เอาต์ที่กำหนดเองในเครื่องมือเขียนได้ที่แหล่งข้อมูลเพิ่มเติมต่อไปนี้
ตัวอย่างแอป
- CanonicalLayouts เป็นแหล่งเก็บแพตเทิร์นการออกแบบที่ผ่านการพิสูจน์แล้วว่ามอบประสบการณ์การใช้งานที่ดีที่สุดแก่ผู้ใช้ในอุปกรณ์หน้าจอขนาดใหญ่
- JetNews แสดงวิธีออกแบบแอปที่ปรับ UI ให้ใช้ประโยชน์จากพื้นที่ที่มีอยู่
- ตอบ คือการตอบสนองต่อตัวอย่างที่รองรับอุปกรณ์เคลื่อนที่ แท็บเล็ต และอุปกรณ์แบบพับได้
- ตอนนี้มีใน Android เป็นแอปที่ใช้เลย์เอาต์ที่ปรับเปลี่ยนได้เพื่อรองรับหน้าจอขนาดต่างๆ
วิดีโอ
แนะนำสำหรับคุณ
- หมายเหตุ: ข้อความลิงก์จะแสดงเมื่อ JavaScript ปิดอยู่
- การแมปคอมโพเนนต์กับโค้ดที่มีอยู่
- ข้อมูลเบื้องต้นเกี่ยวกับการจัดวาง
- ระยะของ Jetpack Compose