विंडो इनसेट सेट अप करना

अपने ऐप्लिकेशन को यह कंट्रोल करने की अनुमति देने के लिए कि वह कॉन्टेंट कहां दिखाए, सेटअप करने के लिए यह तरीका अपनाएं. इन चरणों को पूरा किए बिना, हो सकता है कि आपका ऐप्लिकेशन सिस्टम यूज़र इंटरफ़ेस (यूआई) के पीछे काले या सॉलिड रंग दिखाए. इसके अलावा, यह भी हो सकता है कि ऐप्लिकेशन, सॉफ़्टवेयर कीबोर्ड के साथ सिंक न हो.

  1. Android 15 और उसके बाद के वर्शन पर एज-टू-एज विंडो को लागू करने के लिए, Android 15 (एपीआई लेवल 35) या उसके बाद के वर्शन को टारगेट करें. आपका ऐप्लिकेशन, सिस्टम यूज़र इंटरफ़ेस (यूआई) के पीछे दिखता है. इनसेट मैनेज करके, अपने ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) में बदलाव किया जा सकता है.
  2. इसके अलावा, Activity.onCreate() में enableEdgeToEdge() को कॉल करें. इससे आपके ऐप्लिकेशन को Android के पिछले वर्शन पर एज-टू-एज डिसप्ले किया जा सकता है.
  3. अपनी गतिविधि की AndroidManifest.xml एंट्री में android:windowSoftInputMode="adjustResize" सेट करें. इस सेटिंग की मदद से, आपके ऐप्लिकेशन को सॉफ़्टवेयर IME का साइज़ इनसेट के तौर पर मिलता है. इससे, आपके ऐप्लिकेशन में IME के दिखने और छिपने पर, सही लेआउट और पैडिंग लागू करने में मदद मिलती है.

    <!-- In your AndroidManifest.xml file: -->
    <activity
      android:name=".ui.MainActivity"
      android:label="@string/app_name"
      android:windowSoftInputMode="adjustResize"
      android:theme="@style/Theme.MyApplication"
      android:exported="true">
    

Compose API का इस्तेमाल करना

जब आपकी गतिविधि सभी इनसेट को मैनेज करने का कंट्रोल ले लेती है, तब Compose API का इस्तेमाल करके यह पक्का किया जा सकता है कि कॉन्टेंट छिपा न हो और इंटरैक्ट किए जा सकने वाले एलिमेंट, सिस्टम यूज़र इंटरफ़ेस के साथ ओवरलैप न हों. ये एपीआई, आपके ऐप्लिकेशन के लेआउट को इनसेट में किए गए बदलावों के साथ सिंक भी करते हैं.

उदाहरण के लिए, अपने पूरे ऐप्लिकेशन के कॉन्टेंट में इनसेट लागू करने का यह सबसे बुनियादी तरीका है:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    enableEdgeToEdge()

    setContent {
        Box(Modifier.safeDrawingPadding()) {
            // the rest of the app
        }
    }
}

यह स्निपेट, ऐप्लिकेशन के पूरे कॉन्टेंट के चारों ओर पैडिंग के तौर पर safeDrawing विंडो इनसेट लागू करता है. इससे यह पक्का होता है कि इंटरैक्ट किए जा सकने वाले एलिमेंट, सिस्टम यूज़र इंटरफ़ेस (यूआई) के साथ ओवरलैप न हों. इसका यह भी मतलब है कि ऐप्लिकेशन का कोई भी हिस्सा, किनारों तक दिखने वाला इफ़ेक्ट पाने के लिए, सिस्टम यूज़र इंटरफ़ेस (यूआई) के पीछे नहीं दिखेगा. पूरी विंडो का पूरा फ़ायदा पाने के लिए, आपको यह तय करना होगा कि इनसेट को स्क्रीन के हिसाब से या कॉम्पोनेंट के हिसाब से कहां लागू करना है.

इनसेट के सभी टाइप, एपीआई 21 में वापस पोर्ट किए गए IME ऐनिमेशन के साथ अपने-आप ऐनिमेट होते हैं. इनसेट की वैल्यू बदलने पर, इनसेट का इस्तेमाल करने वाले सभी लेआउट भी अपने-आप ऐनिमेट हो जाते हैं.

अपने Composable लेआउट में बदलाव करने के लिए, इनसेट टाइप का इस्तेमाल करने के दो मुख्य तरीके हैं: पैडिंग मॉडिफ़ायर और इनसेट साइज़ मॉडिफ़ायर.

पैडिंग मॉडिफ़ायर

Modifier.windowInsetsPadding(windowInsets: WindowInsets), दी गई विंडो इनसेट को पैडिंग के तौर पर लागू करता है. यह ठीक वैसे ही काम करता है जैसे Modifier.padding करता है. उदाहरण के लिए, Modifier.windowInsetsPadding(WindowInsets.safeDrawing), सेफ़ ड्रॉइंग इनसेट को चारों तरफ़ पैडिंग के तौर पर लागू करता है.

आम तौर पर इस्तेमाल होने वाले इनसेट टाइप के लिए, कई उपयोगी तरीके पहले से मौजूद हैं. Modifier.safeDrawingPadding() एक ऐसा तरीका है जो Modifier.windowInsetsPadding(WindowInsets.safeDrawing) के बराबर है. इनसे मिलते-जुलते, दूसरे इनसेट टाइप के लिए भी मॉडिफ़ायर उपलब्ध हैं.

इनसेट साइज़ मॉडिफ़ायर

नीचे दिए गए मॉडिफ़ायर, कॉम्पोनेंट के साइज़ को इनसेट के साइज़ के तौर पर सेट करके, विंडो इनसेट की संख्या लागू करते हैं:

Modifier.windowInsetsStartWidth(windowInsets: WindowInsets)

windowInsets के स्टार्ट साइड को चौड़ाई के तौर पर लागू करता है (जैसे कि Modifier.width)

Modifier.windowInsetsEndWidth(windowInsets: WindowInsets)

windowInsets के आखिरी हिस्से को चौड़ाई के तौर पर लागू करता है, जैसे कि Modifier.width

Modifier.windowInsetsTopHeight(windowInsets: WindowInsets)

windowInsets के ऊपरी हिस्से को ऊंचाई के तौर पर लागू करता है (जैसे कि Modifier.height)

Modifier.windowInsetsBottomHeight(windowInsets: WindowInsets)

windowInsets के निचले हिस्से को ऊंचाई के तौर पर लागू करता है, जैसे कि Modifier.height

ये मॉडिफ़ायर, खास तौर पर ऐसे Spacer का साइज़ तय करने के लिए मददगार होते हैं जो इनसेट का स्पेस लेता है:

LazyColumn(
    Modifier.imePadding()
) {
    // Other content
    item {
        Spacer(
            Modifier.windowInsetsBottomHeight(
                WindowInsets.systemBars
            )
        )
    }
}

इनसेट की खपत

इनसेट पैडिंग मॉडिफ़ायर (windowInsetsPadding और safeDrawingPadding जैसे सहायक), इनसेट के उस हिस्से का इस्तेमाल अपने-आप करते हैं जिसे पैडिंग के तौर पर लागू किया जाता है. कॉम्पोज़िशन ट्री में ज़्यादा अंदर जाने पर, नेस्ट किए गए इनसेट पैडिंग मॉडिफ़ायर और इनसेट साइज़ मॉडिफ़ायर को पता चलता है कि इनसेट के कुछ हिस्से का इस्तेमाल, आउटर इनसेट पैडिंग मॉडिफ़ायर ने पहले ही कर लिया है. साथ ही, इनसेट के एक ही हिस्से का एक से ज़्यादा बार इस्तेमाल करने से बचते हैं, क्योंकि इससे बहुत ज़्यादा अतिरिक्त स्पेस बन जाता है.

अगर इनसेट का इस्तेमाल पहले ही किया जा चुका है, तो इनसेट साइज़ में बदलाव करने वाले टूल, इनसेट के एक ही हिस्से का एक से ज़्यादा बार इस्तेमाल करने से भी बचते हैं. हालांकि, इनसे अपने साइज़ में सीधे तौर पर बदलाव किया जाता है. इसलिए, ये इनसेट का इस्तेमाल नहीं करते.

इस वजह से, नेस्ट किए गए पैडिंग मॉडिफ़ायर, हर कॉम्पोज़ेबल पर लागू किए गए पैडिंग की मात्रा को अपने-आप बदल देते हैं.

पहले की तरह ही LazyColumn के उदाहरण को देखें. इसमें imePadding मॉडिफ़ायर की मदद से, LazyColumn का साइज़ बदला जा रहा है. LazyColumn में, आखिरी आइटम का साइज़, सिस्टम बार के सबसे नीचे की ऊंचाई के बराबर होता है:

LazyColumn(
    Modifier.imePadding()
) {
    // Other content
    item {
        Spacer(
            Modifier.windowInsetsBottomHeight(
                WindowInsets.systemBars
            )
        )
    }
}

जब IME बंद होता है, तो imePadding() मॉडिफ़ायर कोई पैडिंग लागू नहीं करता, क्योंकि IME की कोई ऊंचाई नहीं होती. imePadding() मॉडिफ़ायर कोई पैडिंग लागू नहीं कर रहा है, इसलिए कोई इनसेट इस्तेमाल नहीं किया जा रहा है. साथ ही, Spacer की ऊंचाई, सिस्टम बार के सबसे नीचे वाले हिस्से के साइज़ के बराबर होगी.

जब IME खुलता है, तो IME इनसेट, IME के साइज़ से मैच करने के लिए ऐनिमेट होते हैं. साथ ही, IME के खुलने पर imePadding() मॉडिफ़ायर, LazyColumn का साइज़ बदलने के लिए बॉटम पैडिंग लागू करना शुरू कर देता है. imePadding() मॉडिफ़ायर, सबसे नीचे पैडिंग लागू करने के साथ-साथ उतने ही इनसेट का इस्तेमाल भी शुरू कर देता है. इसलिए, Spacer की ऊंचाई कम होने लगती है, क्योंकि imePadding() मॉडिफ़ायर ने सिस्टम बार के लिए स्पेसिंग का कुछ हिस्सा पहले ही लागू कर दिया है. जब imePadding() मॉडिफ़ायर, सबसे नीचे इतना पैडिंग लागू करता है कि वह सिस्टम बार से ज़्यादा हो जाता है, तो Spacer की ऊंचाई शून्य हो जाती है.

IME बंद होने पर, ये बदलाव उलटे क्रम में होते हैं: imePadding() के सिस्टम बार के सबसे नीचे वाले हिस्से से कम लागू होने पर, Spacer शून्य की ऊंचाई से बड़ा होना शुरू हो जाता है. आखिर में, IME पूरी तरह से ऐनिमेशन के साथ बंद होने पर, Spacer की ऊंचाई, सिस्टम बार के सबसे नीचे वाले हिस्से की ऊंचाई से मेल खाती है.

दूसरी इमेज. TextField के साथ, किनारे से किनारे तक लेज़ी कॉलम.
को छिपा सकता है.

यह व्यवहार, सभी windowInsetsPadding मॉडिफ़ायर के बीच बातचीत के ज़रिए पूरा किया जाता है. साथ ही, इस पर कुछ और तरीकों से असर पड़ सकता है.

Modifier.consumeWindowInsets(insets: WindowInsets) भी Modifier.windowInsetsPadding की तरह ही इनसेट का इस्तेमाल करता है. हालांकि, यह इस्तेमाल किए गए इनसेट को पैडिंग के तौर पर लागू नहीं करता. यह इनसेट साइज़ में बदलाव करने वाले टूल के साथ इस्तेमाल करने के लिए मददगार है. इससे, सिबलिंग को यह पता चलता है कि कुछ इनसेट पहले ही इस्तेमाल हो चुके हैं:

Column(Modifier.verticalScroll(rememberScrollState())) {
    Spacer(Modifier.windowInsetsTopHeight(WindowInsets.systemBars))

    Column(
        Modifier.consumeWindowInsets(
            WindowInsets.systemBars.only(WindowInsetsSides.Vertical)
        )
    ) {
        // content
        Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime))
    }

    Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.systemBars))
}

Modifier.consumeWindowInsets(paddingValues: PaddingValues), WindowInsets आर्ग्युमेंट वाले वर्शन की तरह ही काम करता है. हालांकि, इसे इस्तेमाल करने के लिए, मनमुताबिक PaddingValues लेना होता है. यह बच्चों को यह बताने के लिए काम आता है कि जब पैडिंग या स्पेसिंग, इनसेट पैडिंग मॉडिफ़ायर के बजाय किसी दूसरे तरीके से दी जाती है, तो क्या करना चाहिए. जैसे, सामान्य Modifier.padding या तय की गई ऊंचाई वाले स्पेसर्स:

Column(Modifier.padding(16.dp).consumeWindowInsets(PaddingValues(16.dp))) {
    // content
    Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.ime))
}

जिन मामलों में रॉ विंडो इनसेट की ज़रूरत होती है, उनमें सीधे WindowInsets वैल्यू का इस्तेमाल करें. इसके अलावा, WindowInsets.asPaddingValues() का इस्तेमाल करके, उन इनसेट का PaddingValues दिखाएं जिन पर कन्ज़्यूमेशन का असर नहीं पड़ता. हालांकि, नीचे दी गई चेतावनियों की वजह से, जहां भी हो सके वहां विंडो इनसेट पैडिंग में बदलाव करने वाले और विंडो इनसेट के साइज़ में बदलाव करने वाले टूल का इस्तेमाल करें.

इनसेट और Jetpack Compose के फ़ेज़

Compose, इनसेट को अपडेट करने और ऐनिमेट करने के लिए, AndroidX के मुख्य एपीआई का इस्तेमाल करता है. ये एपीआई, इनसेट को मैनेज करने वाले प्लैटफ़ॉर्म एपीआई का इस्तेमाल करते हैं. प्लैटफ़ॉर्म के इस व्यवहार की वजह से, इनसेट का Jetpack Compose के चरणों से खास संबंध है.

इनसेट की वैल्यू, कंपोज़िशन फ़ेज़ के बाद अपडेट की जाती है, लेकिन लेआउट फ़ेज़ के पहले. इसका मतलब है कि कॉम्पोज़िशन में इनसेट की वैल्यू पढ़ने के लिए, आम तौर पर इनसेट की उस वैल्यू का इस्तेमाल किया जाता है जो एक फ़्रेम पहले की होती है. इस पेज पर बताए गए, पहले से मौजूद मॉडिफ़ायर, इनसेट की वैल्यू का इस्तेमाल, लेआउट फ़ेज़ तक करने में देरी करने के लिए बनाए गए हैं. इससे यह पक्का होता है कि इनसेट की वैल्यू, अपडेट होने के बाद उसी फ़्रेम पर इस्तेमाल की जाती हैं.