WindowInsets
คือ API มาตรฐานใน Jetpack Compose สำหรับการจัดการพื้นที่ของหน้าจอที่ UI ของระบบบดบังบางส่วนหรือทั้งหมด
โดย
พื้นที่เหล่านี้รวมถึงแถบสถานะ แถบนำทาง และแป้นพิมพ์บนหน้าจอ หรือจะส่ง WindowInsetsRulers
ที่กำหนดไว้ล่วงหน้า เช่น SafeDrawing
ไปยัง Modifier.fitInside
หรือ Modifier.fitOutside
เพื่อจัดแนวเนื้อหาให้ตรงกับแถบระบบและรอยบากของจอแสดงผล หรือสร้าง WindowInsetsRulers
ที่กำหนดเองก็ได้
ข้อดีของ WindowInsetsRulers
- หลีกเลี่ยงความซับซ้อนในการใช้งาน: ทำงานในระยะการจัดวาง
ของเลย์เอาต์ ซึ่งหมายความว่าการดำเนินการนี้จะข้ามเชนการบริโภคที่แทรกอย่างสมบูรณ์ และจะระบุตำแหน่งที่ถูกต้องและแน่นอนของแถบระบบและรอยบากของจอแสดงผลได้เสมอ ไม่ว่าเลย์เอาต์ระดับบนสุดจะทำอะไรก็ตาม การใช้เมธอด
Modifier.fitInside
หรือModifier.fitOutside
จะช่วยแก้ไข ปัญหาเมื่อ Composable บรรพบุรุษใช้ Insets อย่างไม่ถูกต้อง - หลีกเลี่ยงแถบระบบได้อย่างง่ายดาย: ช่วยให้เนื้อหาแอปหลีกเลี่ยงแถบระบบ
และรอยบากบนจอแสดงผล และอาจตรงไปตรงมากว่าการใช้
WindowInsets
โดยตรง - ปรับแต่งได้สูง: นักพัฒนาแอปสามารถจัดเนื้อหาให้สอดคล้องกับไม้บรรทัดที่กำหนดเอง และควบคุมเลย์เอาต์ได้อย่างแม่นยำด้วยเลย์เอาต์ที่กำหนดเอง
ข้อเสียของ WindowInsetsRulers
- ใช้สําหรับการวัดผลไม่ได้: เนื่องจากทํางานในระหว่างระยะการจัดวาง ข้อมูลตําแหน่งที่ให้จึงไม่พร้อมใช้งานในระหว่าง ระยะการวัดผลก่อนหน้านี้
ปรับเนื้อหาให้สอดคล้องกับวิธีการแก้ไข
Modifier.fitInside
อนุญาตให้แอปจัดแนวเนื้อหาให้ตรงกับแถบระบบและรอยบากของจอแสดงผล
โดยใช้แทน WindowInsets
ได้ Modifier.fitOutside
มักจะเป็นค่าผกผันของ Modifier.fitInside
เช่น หากต้องการยืนยันว่าเนื้อหาของแอปหลีกเลี่ยงแถบระบบและส่วนที่ตัดออกของจอแสดงผล คุณสามารถใช้ fitInside(WindowInsetsRulers.safeDrawing.current)
ได้
@Composable fun FitInsideDemo(modifier: Modifier) { Box( modifier = modifier .fillMaxSize() // Or DisplayCutout, Ime, NavigationBars, StatusBar, etc... .fitInside(WindowInsetsRulers.SafeDrawing.current) ) }
ตารางต่อไปนี้แสดงลักษณะเนื้อหาแอปของคุณเมื่อใช้
ไม้บรรทัดที่กำหนดไว้ล่วงหน้าโดยมี Modifier.fitInside
หรือ Modifier.fitOutside
ประเภทไม้บรรทัดที่กำหนดไว้ล่วงหน้า | ||
---|---|---|
![]() |
![]() |
|
![]() |
ไม่มี |
|
![]() |
![]() |
|
![]() |
ไม่มี (ใช้ |
|
![]() |
![]() |
การใช้ Modifier.fitInside
และ Modifier.fitOutside
ต้องมีการจำกัด Composable ซึ่งหมายความว่าคุณต้องกำหนดตัวแก้ไข เช่น
Modifier.size
หรือ Modifier.fillMaxSize
ไม้บรรทัดบางอัน เช่น Modifier.fitOutside
ใน SafeDrawing
และ SystemBars
จะแสดง
ไม้บรรทัดหลายอัน ในกรณีนี้ Android จะวาง Composable โดยใช้ไม้บรรทัด 1 อัน
จากซ้าย บน ขวา ล่าง
หลีกเลี่ยง IME ด้วย Modifier.fitInside
หากต้องการจัดการองค์ประกอบด้านล่างด้วย IME ที่มี Modifier.fitInside
ให้ส่ง RectRuler
ที่ใช้ค่าด้านในสุดของ NavigationBar
และ Ime
@Composable fun FitInsideWithImeDemo(modifier: Modifier) { Box( modifier = modifier .fillMaxSize() .fitInside( RectRulers.innermostOf( WindowInsetsRulers.NavigationBars.current, WindowInsetsRulers.Ime.current ) ) ) { TextField( value = "Demo IME Insets", onValueChange = {}, modifier = modifier.align(Alignment.BottomStart).fillMaxWidth() ) } }
หลีกเลี่ยงแถบสถานะและแถบคําบรรยายแทนเสียงด้วย Modifier.fitInside
ในทำนองเดียวกัน หากต้องการยืนยันองค์ประกอบด้านบน ให้หลีกเลี่ยงแถบสถานะและแถบคําบรรยายแทนเสียงพร้อมกับ Modifier.fitInsider
ให้ส่ง RectRuler
ที่ใช้ค่าด้านในสุดของ StatusBars
และ CaptionBar
@Composable fun FitInsideWithStatusAndCaptionBarDemo(modifier: Modifier) { Box( modifier = modifier .fillMaxSize() .fitInside( RectRulers.innermostOf( WindowInsetsRulers.StatusBars.current, WindowInsetsRulers.CaptionBar.current ) ) ) }
สร้าง WindowInsetsRulers
ที่กำหนดเอง
คุณจัดแนวเนื้อหากับไม้บรรทัดที่กำหนดเองได้ ตัวอย่างเช่น พิจารณากรณีการใช้งานที่ Composable หลักจัดการ Inset อย่างไม่ถูกต้อง ซึ่งทำให้เกิดปัญหาการเว้นวรรคใน Composable ย่อยที่อยู่ปลายน้ำ
แม้ว่าปัญหานี้จะแก้ไขได้ด้วยวิธีอื่นๆ รวมถึงการใช้ Modifier.fitInside
แต่คุณก็สร้างไม้บรรทัดที่กำหนดเองเพื่อจัดแนว Composable ขององค์ประกอบย่อยได้อย่างแม่นยำโดยไม่ต้องแก้ไขปัญหาในองค์ประกอบหลักต้นทางได้เช่นกัน ดังตัวอย่างและวิดีโอต่อไปนี้
@Composable fun WindowInsetsRulersDemo(modifier: Modifier) { Box( contentAlignment = BottomCenter, modifier = modifier .fillMaxSize() // The mistake that causes issues downstream, as .padding doesn't consume insets. // While it's correct to instead use .windowInsetsPadding(WindowInsets.navigationBars), // assume it's difficult to identify this issue to see how WindowInsetsRulers can help. .padding(WindowInsets.navigationBars.asPaddingValues()) ) { TextField( value = "Demo IME Insets", onValueChange = {}, modifier = modifier // Use alignToSafeDrawing() instead of .imePadding() to precisely place this child // Composable without having to fix the parent upstream. .alignToSafeDrawing() // .imePadding() // .fillMaxWidth() ) } } fun Modifier.alignToSafeDrawing(): Modifier { return layout { measurable, constraints -> if (constraints.hasBoundedWidth && constraints.hasBoundedHeight) { val placeable = measurable.measure(constraints) val width = placeable.width val height = placeable.height layout(width, height) { val bottom = WindowInsetsRulers.SafeDrawing.current.bottom .current(0f).roundToInt() - height val right = WindowInsetsRulers.SafeDrawing.current.right .current(0f).roundToInt() val left = WindowInsetsRulers.SafeDrawing.current.left .current(0f).roundToInt() measurable.measure(Constraints.fixed(right - left, height)) .place(left, bottom) } } else { val placeable = measurable.measure(constraints) layout(placeable.width, placeable.height) { placeable.place(0, 0) } } } }
วิดีโอต่อไปนี้แสดงตัวอย่างการใช้ IME ที่มีปัญหา
ซึ่งเกิดจากองค์ประกอบหลักต้นทางในรูปภาพทางด้านซ้าย และการใช้ไม้บรรทัดที่กำหนดเอง
เพื่อแก้ไขปัญหาทางด้านขวา โดยจะมีการแสดงระยะห่างเพิ่มเติมใต้ TextField
Composable เนื่องจากองค์ประกอบระดับบนไม่ได้ใช้ระยะห่างของแถบนำทาง โดยวาง
child ในตำแหน่งที่ถูกต้องในรูปภาพด้านขวาโดยใช้ไม้บรรทัดที่กำหนดเอง
ดังที่เห็นในโค้ดตัวอย่างก่อนหน้า
ยืนยันว่าผู้ปกครองถูกจำกัด
หากต้องการใช้ WindowInsetsRulers
อย่างปลอดภัย โปรดตรวจสอบว่าผู้ปกครองได้ระบุข้อจำกัดที่ถูกต้อง
ผู้ปกครองต้องมีขนาดที่กำหนดไว้และไม่สามารถอิงตามขนาดของบุตรหลานที่ใช้ WindowInsetsRulers
ใช้ fillMaxSize
หรือตัวแก้ไขขนาดอื่นๆ
ใน Composable หลัก
ในทำนองเดียวกัน การวาง Composable ที่ใช้ WindowInsetsRulers
ภายใน
คอนเทนเนอร์เลื่อน เช่น verticalScroll
อาจทำให้เกิดลักษณะการทำงานที่ไม่คาดคิด เนื่องจาก
คอนเทนเนอร์เลื่อนมีข้อจำกัดด้านความสูงที่ไม่จำกัด ซึ่ง
ไม่สอดคล้องกับตรรกะของไม้บรรทัด