WindowInsetsRulers hakkında

WindowInsets, ekranın sistem kullanıcı arayüzü tarafından kısmen veya tamamen kapatılan alanlarını işlemek için Jetpack Compose'daki standart API'dir. Bu alanlar arasında durum çubuğu, gezinme çubuğu ve ekran klavyesi bulunur. Alternatif olarak, içeriğinizi sistem çubukları ve ekran kesimiyle hizalamak için önceden tanımlanmış WindowInsetsRulers'ları (ör. SafeDrawing) Modifier.fitInside'a veya Modifier.fitOutside'a iletebilir ya da özel WindowInsetsRulers oluşturabilirsiniz.

WindowInsetsRulers avantajları

  • Tüketim Karmaşıklığını Önler: Düzenin yerleştirme aşamasında çalışır. Bu nedenle, yerleştirilmiş tüketim zincirini tamamen atlar ve üst düzenlerin ne yaptığına bakılmaksızın sistem çubuklarının ve ekran kesiklerinin doğru ve mutlak konumlarını her zaman sağlayabilir. Modifier.fitInside veya Modifier.fitOutside yöntemlerini kullanmak, üst composable'lar yerleştirmeleri yanlış tükettiğinde sorunları düzeltmeye yardımcı olur.
  • Sistem çubuklarından kolayca kaçının: Uygulama içeriğinizin sistem çubuklarından ve ekran kesiminden kaçınmasına yardımcı olur. Ayrıca, doğrudan WindowInsets kullanmaktan daha kolay olabilir.
  • Yüksek düzeyde özelleştirilebilir: Geliştiriciler, içerikleri özel cetvellerle hizalayabilir ve özel düzenlerle düzenleri üzerinde hassas kontrol sahibi olabilir.

WindowInsetsRulers ile ilgili dezavantajlar

  • Ölçüm için kullanılamaz: Yerleştirme aşamasında çalıştığı için sağladığı konumsal bilgiler, önceki ölçüm aşamasında kullanılamaz.

İçeriğinizi değiştirici yöntemlerle uyumlu hale getirme

Modifier.fitInside, uygulamaların içeriği sistem çubuklarıyla hizalamasına ve ekran kesiklerini göstermesine olanak tanır. WindowInsets yerine kullanılabilir. Modifier.fitOutside genellikle Modifier.fitInside'ün tersidir.

Örneğin, uygulama içeriğinin sistem çubuklarından ve ekran kesiminden kaçındığını doğrulamak için fitInside(WindowInsetsRulers.safeDrawing.current) kullanabilirsiniz.

@Composable
fun FitInsideDemo(modifier: Modifier) {
    Box(
        modifier = modifier
            .fillMaxSize()
            // Or DisplayCutout, Ime, NavigationBars, StatusBar, etc...
            .fitInside(WindowInsetsRulers.SafeDrawing.current)
    )
}

Aşağıdaki tabloda, uygulamanızın içeriğinin Modifier.fitInside veya Modifier.fitOutside ile önceden tanımlanmış cetvellerle nasıl görüneceği gösterilmektedir.

Önceden tanımlanmış cetvel türü

Modifier.fitInside

Modifier.fitOutside

DisplayCutout

Ime

Yok

NavigationBars

SafeDrawing

Geçersiz (Bunun yerine StatusBar, CaptionBar, NavigationBar politikalarını kullanın)

StatusBar

Modifier.fitInside ve Modifier.fitOutside kullanmak için composable'ların kısıtlanması gerekir. Bu, Modifier.size veya Modifier.fillMaxSize gibi değiştiriciler tanımlamanız gerektiği anlamına gelir.

Modifier.fitOutside ve SystemBars gibi bazı cetveller birden fazla cetvel döndürür.SafeDrawing Bu durumda Android, Composable'ı soldan, üstten, sağdan veya alttan bir cetvelle yerleştirir.

Modifier.fitInside ile IME'den kaçınma

Modifier.fitInside ile bir IME'de alttaki öğeleri işlemek için NavigationBar ve Ime öğelerinin en içteki değerini alan bir RectRuler iletin.

@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 ile durum çubuğu ve başlık çubuğundan kaçınma

Benzer şekilde, üst öğeleri doğrulamak için durum çubuğu ve başlık çubuğunu Modifier.fitInsider ile birlikte kullanmaktan kaçının. Bunun yerine, StatusBars ve CaptionBar öğelerinin en içteki değerini alan bir RectRuler iletin.

@Composable
fun FitInsideWithStatusAndCaptionBarDemo(modifier: Modifier) {
    Box(
        modifier = modifier
            .fillMaxSize()
            .fitInside(
                RectRulers.innermostOf(
                    WindowInsetsRulers.StatusBars.current,
                    WindowInsetsRulers.CaptionBar.current
                )
            )
    )
}

Özel WindowInsetsRulers oluşturma

İçeriği özel cetvellerle hizalayabilirsiniz. Örneğin, bir üst composable'ın, yerleştirmeleri yanlış şekilde işleyerek alt öğede dolgu sorunlarına neden olduğu kullanım alanını ele alalım. Bu sorun, Modifier.fitInside kullanmak gibi başka yöntemlerle de çözülebilse de aşağıdaki örnekte ve videoda gösterildiği gibi, üst öğede sorunu düzeltmeden alt öğeyi tam olarak hizalamak için özel bir cetvel de oluşturabilirsiniz:

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

Aşağıdaki videoda, soldaki resimde yer alan bir üst öğenin neden olduğu sorunlu IME ekleme tüketimi örneği ve sağ tarafta sorunu düzeltmek için özel cetvellerin kullanımı gösterilmektedir. Gezinme çubuğu dolgusu üst öğe tarafından kullanılmadığı için TextField Composable'ın altında ekstra dolgu gösteriliyor. Çocuk, önceki kod örneğinde gösterildiği gibi özel bir cetvel kullanılarak sağdaki resimde doğru konuma yerleştiriliyor.

Ebeveynlerin kısıtlandığını doğrulayın

WindowInsetsRulers özelliğini güvenli bir şekilde kullanmak için ebeveynin geçerli kısıtlamalar sağladığından emin olun. Ebeveynlerin tanımlanmış bir boyutu olmalıdır ve WindowInsetsRulers kullanan bir çocuğun boyutuna bağlı olamaz. Üst composable'larda fillMaxSize veya diğer boyut değiştiricileri kullanın.

Benzer şekilde, WindowInsetsRulers kullanan bir composable'ı verticalScroll gibi kaydırma kapsayıcısının içine yerleştirmek de beklenmedik davranışlara neden olabilir. Bunun nedeni, kaydırma kapsayıcısının, cetvelin mantığıyla uyumlu olmayan sınırsız yükseklik kısıtlamaları sağlamasıdır.