Tentang WindowInsetsRulers

WindowInsets adalah API standar di Jetpack Compose untuk menangani area layar yang sebagian atau seluruhnya tertutup oleh UI sistem. Area ini mencakup status bar, menu navigasi, dan keyboard virtual. Sebagai alternatif, Anda dapat meneruskan WindowInsetsRulers yang telah ditentukan sebelumnya seperti SafeDrawing ke Modifier.fitInside atau Modifier.fitOutside untuk menyelaraskan konten Anda dengan kolom sistem dan potongan layar atau membuat WindowInsetsRulers kustom.

Keuntungan WindowInsetsRulers

  • Menghindari Kompleksitas Penggunaan: Beroperasi selama fase penempatan tata letak. Artinya, ini sepenuhnya melewati rantai konsumsi inset dan selalu dapat memberikan posisi absolut yang benar dari kolom sistem dan potongan layar, terlepas dari apa yang telah dilakukan tata letak induk. Penggunaan metode Modifier.fitInside atau Modifier.fitOutside berguna dalam memperbaiki masalah saat Composable induk menggunakan inset secara tidak benar.
  • Menghindari kolom sistem dengan mudah: Membantu konten aplikasi Anda menghindari kolom sistem dan potongan layar, serta dapat lebih mudah daripada menggunakan WindowInsets secara langsung.
  • Sangat dapat disesuaikan: Developer dapat menyelaraskan konten dengan penggaris kustom, dan memiliki kontrol yang akurat atas tata letak mereka dengan tata letak kustom.

Kekurangan WindowInsetsRulers

  • Tidak dapat digunakan untuk Pengukuran: Karena beroperasi selama fase penempatan, informasi posisi yang diberikannya tidak tersedia selama fase pengukuran sebelumnya.
  • Potensi Ketidakstabilan Tata Letak: Hal ini dapat menyebabkan error jika ukuran tata letak induk bergantung pada ukuran turunannya. Karena turunan yang menggunakan WindowInsetsRulers dapat mengubah posisi atau ukurannya selama penempatan, hal ini dapat membuat siklus tata letak yang tidak stabil.

Membuat WindowInsetsRulers kustom

Anda dapat menyelaraskan konten dengan penggaris kustom. Misalnya, pertimbangkan kasus penggunaan saat composable induk menangani inset secara tidak benar sehingga menyebabkan masalah padding di turunan hilir. Meskipun masalah ini dapat diselesaikan dengan cara lain, termasuk dengan menggunakan Modifier.fitInside, Anda juga dapat membuat penggaris kustom untuk menyelaraskan composable turunan secara presisi tanpa harus memperbaiki masalah di induk upstream seperti yang ditunjukkan dalam contoh dan video berikut:

@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)
            }
        }
    }
}

Video berikut menunjukkan contoh konsumsi inset IME yang bermasalah yang disebabkan oleh induk upstream dalam gambar di sebelah kiri, dan menggunakan penggaris kustom untuk memperbaiki masalah di sebelah kanan. Padding tambahan ditampilkan di bawah Composable TextField karena padding menu navigasi tidak digunakan oleh induk. Anak ditempatkan di lokasi yang benar dalam gambar kanan menggunakan penggaris kustom seperti yang terlihat dalam contoh kode sebelumnya.

Verifikasi bahwa orang tua dibatasi

Untuk menggunakan WindowInsetsRulers dengan aman, pastikan induk memberikan batasan yang valid. Induk harus memiliki ukuran yang ditentukan dan tidak dapat bergantung pada ukuran turunan yang menggunakan WindowInsetsRulers. Gunakan fillMaxSize atau pengubah ukuran lainnya pada Composable induk.

Demikian pula, menempatkan composable yang menggunakan WindowInsetsRulers di dalam penampung scroll seperti verticalScroll dapat menyebabkan perilaku yang tidak terduga karena penampung scroll memberikan batasan tinggi yang tidak terbatas, yang tidak kompatibel dengan logika penggaris.