WindowInsetsRulers के बारे में जानकारी

WindowInsets, Jetpack Compose में स्टैंडर्ड एपीआई है. इसका इस्तेमाल, स्क्रीन के उन हिस्सों को मैनेज करने के लिए किया जाता है जो सिस्टम यूज़र इंटरफ़ेस (यूआई) की वजह से पूरी तरह या कुछ हद तक दिख नहीं पाते. इनमें स्टेटस बार, नेविगेशन बार, और ऑन-स्क्रीन कीबोर्ड शामिल हैं. इसके अलावा, पहले से तय किए गए WindowInsetsRulers जैसे कि SafeDrawing को Modifier.fitInside या Modifier.fitOutside पर पास किया जा सकता है, ताकि आपके कॉन्टेंट को सिस्टम बार और डिसप्ले कटआउट के साथ अलाइन किया जा सके. इसके अलावा, कस्टम WindowInsetsRulers भी बनाए जा सकते हैं.

WindowInsetsRulers के फ़ायदे

  • कॉन्टेंट को समझने में आसानी होती है: यह लेआउट के प्लेसमेंट फ़ेज़ के दौरान काम करता है. इसका मतलब है कि यह इनसेट इस्तेमाल करने की पूरी चेन को बायपास कर देता है. साथ ही, यह सिस्टम बार और डिसप्ले कटआउट की सही और सटीक पोज़िशन हमेशा दे सकता है. भले ही, पैरंट लेआउट ने कुछ भी किया हो. जब पैरंट कंपोज़ेबल, इंसर्ट का गलत तरीके से इस्तेमाल करते हैं, तब Modifier.fitInside या Modifier.fitOutside तरीकों का इस्तेमाल करके समस्याओं को ठीक किया जा सकता है.
  • सिस्टम बार से आसानी से बचें: इससे आपके ऐप्लिकेशन का कॉन्टेंट, सिस्टम बार और डिसप्ले कटआउट से बचता है. साथ ही, यह 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

DisplayCutout

Ime

लागू नहीं

NavigationBars

SafeDrawing

लागू नहीं (इसके बजाय, StatusBar, CaptionBar, NavigationBar का इस्तेमाल करें)

StatusBar

Modifier.fitInside और Modifier.fitOutside का इस्तेमाल करने के लिए, कंपोज़ेबल को सीमित करना ज़रूरी है. इसका मतलब है कि आपको Modifier.size या Modifier.fillMaxSize जैसे मॉडिफ़ायर तय करने होंगे.

SafeDrawing और SystemBars पर मौजूद Modifier.fitOutside जैसे कुछ रूलर, एक से ज़्यादा रूलर दिखाते हैं. इस मामले में, Android, कंपोज़ेबल को बाईं, ऊपर, दाईं, और नीचे की ओर से एक रूलर का इस्तेमाल करके रखता है.

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 बनाएं

कॉन्टेंट को कस्टम रूलर के साथ अलाइन किया जा सकता है. उदाहरण के लिए, इस्तेमाल का ऐसा उदाहरण देखें जहां पैरंट कंपोज़ेबल, इंसर्ट को ठीक से हैंडल नहीं करता है. इससे डाउनस्ट्रीम चाइल्ड में पैडिंग से जुड़ी समस्याएं होती हैं. इस समस्या को अन्य तरीकों से भी हल किया जा सकता है. जैसे, Modifier.fitInside का इस्तेमाल करके. हालांकि, कस्टम रूलर बनाकर भी चाइल्ड कंपोज़ेबल को सटीक तरीके से अलाइन किया जा सकता है. इसके लिए, पैरंट अपस्ट्रीम में समस्या को ठीक करने की ज़रूरत नहीं होती. यहां दिए गए उदाहरण और वीडियो में देखें:

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

इस वीडियो में, आईएमई इनसेट के इस्तेमाल से जुड़ी समस्या का उदाहरण दिखाया गया है. यह समस्या, बाईं ओर मौजूद इमेज में अपस्ट्रीम पैरंट की वजह से हुई है. साथ ही, दाईं ओर इस समस्या को ठीक करने के लिए, कस्टम रूलर का इस्तेमाल किया गया है. TextField Composable के नीचे अतिरिक्त पैडिंग दिख रही है, क्योंकि नेविगेशन बार की पैडिंग का इस्तेमाल पैरंट ने नहीं किया था. ऊपर दिए गए कोड सैंपल में, कस्टम रूलर का इस्तेमाल करके बच्चे को दाईं ओर मौजूद इमेज में सही जगह पर रखा गया है.

पुष्टि करें कि माता-पिता के लिए पाबंदियां लागू हैं

WindowInsetsRulers का सुरक्षित तरीके से इस्तेमाल करने के लिए, पक्का करें कि माता-पिता या अभिभावक मान्य पाबंदियां लगाएं. पैरंट का साइज़ तय होना चाहिए. साथ ही, यह WindowInsetsRulers का इस्तेमाल करने वाले बच्चे के साइज़ पर निर्भर नहीं होना चाहिए. पैरंट कंपोज़ेबल पर fillMaxSize या अन्य साइज़ मॉडिफ़ायर का इस्तेमाल करें.

इसी तरह, WindowInsetsRulers का इस्तेमाल करने वाले कंपोज़ेबल को verticalScroll जैसे स्क्रोलिंग कंटेनर में रखने से, गड़बड़ी हो सकती है. ऐसा इसलिए, क्योंकि स्क्रोलिंग कंटेनर, ऊंचाई से जुड़ी ऐसी पाबंदियां लगाता है जो रूलर के लॉजिक के साथ काम नहीं करती हैं.