เกี่ยวกับ WindowInsetsRulers

WindowInsets คือ API มาตรฐานใน Jetpack Compose สำหรับการจัดการพื้นที่ของหน้าจอที่ UI ของระบบบดบังบางส่วนหรือทั้งหมด โดย พื้นที่เหล่านี้รวมถึงแถบสถานะ แถบนำทาง และแป้นพิมพ์บนหน้าจอ หรือจะส่ง WindowInsetsRulers ที่กำหนดไว้ล่วงหน้า เช่น SafeDrawing ไปยัง Modifier.fitInside หรือ Modifier.fitOutside เพื่อจัดแนวเนื้อหาให้ตรงกับแถบระบบและรอยบากของจอแสดงผล หรือสร้าง WindowInsetsRulers ที่กำหนดเองก็ได้

ข้อดีของ WindowInsetsRulers

  • หลีกเลี่ยงความซับซ้อนในการใช้งาน: ทำงานในระยะการจัดวาง ของเลย์เอาต์ ซึ่งหมายความว่าการดำเนินการนี้จะข้ามเชนการบริโภคที่แทรกอย่างสมบูรณ์ และจะระบุตำแหน่งที่ถูกต้องและแน่นอนของแถบระบบและรอยบากของจอแสดงผลได้เสมอ ไม่ว่าเลย์เอาต์ระดับบนสุดจะทำอะไรก็ตาม การใช้เมธอด Modifier.fitInside หรือ Modifier.fitOutside จะช่วยแก้ปัญหา เมื่อ Composable บรรพบุรุษใช้ Insets อย่างไม่ถูกต้อง
  • หลีกเลี่ยงแถบระบบได้อย่างง่ายดาย: ช่วยให้เนื้อหาแอปหลีกเลี่ยงแถบระบบ และรอยบากบนจอแสดงผล และอาจตรงไปตรงมากว่าการใช้ WindowInsets โดยตรง
  • ปรับแต่งได้สูง: นักพัฒนาแอปสามารถจัดเนื้อหาให้สอดคล้องกับไม้บรรทัดที่กำหนดเอง และควบคุมเลย์เอาต์ได้อย่างแม่นยำด้วยเลย์เอาต์ที่กำหนดเอง

ข้อเสียของ WindowInsetsRulers

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

สร้าง 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 อาจทำให้เกิดลักษณะการทำงานที่ไม่คาดคิด เนื่องจาก คอนเทนเนอร์เลื่อนมีข้อจำกัดด้านความสูงที่ไม่จำกัด ซึ่ง ไม่สอดคล้องกับตรรกะของไม้บรรทัด