अलग-अलग डिसप्ले साइज़ के साथ काम करना

अलग-अलग डिसप्ले साइज़ के लिए सहायता की सुविधा से, आपके ऐप्लिकेशन को अलग-अलग तरह के डिवाइसों और ज़्यादा से ज़्यादा उपयोगकर्ताओं के लिए ऐक्सेस किया जा सकता है.

अपने ऐप्लिकेशन के लेआउट को रिस्पॉन्सिव और अडैप्टिव डिज़ाइन करें, ताकि वे ज़्यादा से ज़्यादा डिसप्ले साइज़ के साथ काम कर सकें. भले ही, वे अलग-अलग डिवाइस की स्क्रीन हों या मल्टी-विंडो मोड में अलग-अलग ऐप्लिकेशन विंडो हों. रिस्पॉन्सिव/अडैप्टिव लेआउट, डिसप्ले के साइज़ के बावजूद उपयोगकर्ता को बेहतर अनुभव देते हैं. इनकी मदद से, आपके ऐप्लिकेशन को फ़ोन, टैबलेट, फ़ोल्ड किए जा सकने वाले डिवाइस, ChromeOS डिवाइसों, पोर्ट्रेट और लैंडस्केप ओरिएंटेशन, और स्प्लिट-स्क्रीन मोड और डेस्कटॉप विंडो जैसे डिसप्ले कॉन्फ़िगरेशन में इस्तेमाल किया जा सकता है.

रिस्पॉन्सिव/अडैप्टिव लेआउट, डिसप्ले के लिए उपलब्ध स्पेस के हिसाब से बदलते हैं. बदलावों में, स्पेस को भरने वाले छोटे लेआउट अडजस्टमेंट (रिस्पॉन्सिव डिज़ाइन) से लेकर, एक लेआउट को पूरी तरह से दूसरे लेआउट से बदलने तक शामिल हैं, ताकि आपका ऐप्लिकेशन अलग-अलग डिसप्ले साइज़ (अडैप्टिव डिज़ाइन) के हिसाब से सबसे बेहतर तरीके से काम कर सके.

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

कॉन्टेंट-लेवल के कॉम्पोज़ेबल के लिए, लेआउट में बड़े बदलाव करने की सुविधा को साफ़ तौर पर बताना

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

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

पहली इमेज. फ़ोन, फ़ोल्ड किए जा सकने वाले डिवाइस, टैबलेट, और लैपटॉप के फ़ॉर्म फ़ैक्टर

टैबलेट पर, कोई ऐप्लिकेशन मल्टी-विंडो मोड में चल रहा हो. इसका मतलब है कि ऐप्लिकेशन, स्क्रीन को किसी दूसरे ऐप्लिकेशन के साथ बांट रहा हो. डेस्कटॉप विंडो मोड या ChromeOS पर, हो सकता है कि कोई ऐप्लिकेशन ऐसी विंडो में हो जिसका साइज़ बदला जा सकता हो. फ़ोल्ड किए जा सकने वाले डिवाइस में, एक से ज़्यादा फ़िज़िकल स्क्रीन भी हो सकती हैं. इन सभी मामलों में, कॉन्टेंट को दिखाने के तरीके का फ़ैसला लेने के लिए, स्क्रीन का साइज़ मायने नहीं रखता.

इसके बजाय, आपको स्क्रीन के उस हिस्से के आधार पर फ़ैसले लेने चाहिए जो आपके ऐप्लिकेशन के लिए तय किया गया है. इस हिस्से के बारे में, Jetpack WindowManager लाइब्रेरी से मिली मौजूदा विंडो मेट्रिक से पता चलता है. Compose ऐप्लिकेशन में WindowManager का इस्तेमाल करने का उदाहरण देखने के लिए, JetNews का सैंपल देखें.

अपने लेआउट को डिसप्ले के उपलब्ध स्पेस के हिसाब से अडैप्टिव बनाने से, ChromeOS जैसे प्लैटफ़ॉर्म और टैबलेट और फ़ोल्डेबल जैसे फ़ॉर्म फ़ैक्टर के साथ काम करने के लिए, ज़्यादा खास हैंडल करने की ज़रूरत नहीं पड़ती.

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

@Composable
fun MyApp(
    windowSizeClass: WindowSizeClass = currentWindowAdaptiveInfo().windowSizeClass
) {
    // Perform logic on the size class to decide whether to show the top app bar.
    val showTopAppBar = windowSizeClass.windowHeightSizeClass != WindowHeightSizeClass.COMPACT

    // MyScreen knows nothing about window sizes, and performs logic based on a Boolean flag.
    MyScreen(
        showTopAppBar = showTopAppBar,
        /* ... */
    )
}

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

नेस्ट किए गए फ़्लेक्सिबल कॉम्पोज़ेबल को फिर से इस्तेमाल किया जा सकता है

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

नेस्ट किए गए ऐसे कॉम्पोज़ेबल की कल्पना करें जो सूची-ज़्यादा जानकारी वाले लेआउट को लागू करता है. यह एक पैनल या दो पैनल को एक साथ दिखा सकता है:

एक ऐप्लिकेशन, जिसमें दो पैनल एक साथ दिख रहे हैं.
दूसरी इमेज. सूची और ज़्यादा जानकारी वाले लेआउट को दिखाने वाला ऐप्लिकेशन—1, सूची वाला सेक्शन है; 2, ज़्यादा जानकारी वाला सेक्शन है.

सूची की जानकारी का फ़ैसला, ऐप्लिकेशन के पूरे लेआउट का हिस्सा होना चाहिए, ताकि फ़ैसला कॉन्टेंट-लेवल के कॉम्पोज़ेबल से पास किया जा सके:

@Composable
fun AdaptivePane(
    showOnePane: Boolean,
    /* ... */
) {
    if (showOnePane) {
        OnePane(/* ... */)
    } else {
        TwoPane(/* ... */)
    }
}

अगर आपको डिसप्ले के उपलब्ध स्पेस के आधार पर, कॉम्पोज़ेबल का लेआउट अपने-आप बदलने की सुविधा चाहिए, तो क्या होगा? उदाहरण के लिए, ऐसा कार्ड जो जगह होने पर ज़्यादा जानकारी दिखाता हो? आपको किसी उपलब्ध डिसप्ले साइज़ के आधार पर कुछ लॉजिक लागू करना है, लेकिन कौनसा साइज़?

तीसरी इमेज. सिर्फ़ आइकॉन और टाइटल दिखाने वाला छोटा कार्ड और आइकॉन, टाइटल, और कम शब्दों में जानकारी दिखाने वाला बड़ा कार्ड.

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

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

उस चौड़ाई का इस्तेमाल करें जो कॉम्पोज़ेबल को रेंडर करने के लिए दी गई है. इस चौड़ाई को पाने के लिए, आपके पास ये दो विकल्प हैं:

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

  • अगर आपको क्या दिखाना है, तो BoxWithConstraints का इस्तेमाल करें. BoxWithConstraints, मेज़रमेंट से जुड़ी पाबंदियां उपलब्ध कराता है. इनका इस्तेमाल, उपलब्ध डिसप्ले स्पेस के आधार पर अलग-अलग कॉम्पोज़ेबल को कॉल करने के लिए किया जा सकता है. हालांकि, इसके लिए कुछ कीमत चुकानी पड़ती है, क्योंकि BoxWithConstraintsलेआउट के चरण तक कॉम्पोज़िशन को तब तक के लिए रोक देता है, जब तक इन सीमाओं के बारे में पता नहीं चल जाता. इस वजह से, लेआउट के दौरान ज़्यादा काम करना पड़ता है.

@Composable
fun Card(/* ... */) {
    BoxWithConstraints {
        if (maxWidth < 400.dp) {
            Column {
                Image(/* ... */)
                Title(/* ... */)
            }
        } else {
            Row {
                Column {
                    Title(/* ... */)
                    Description(/* ... */)
                }
                Image(/* ... */)
            }
        }
    }
}

पक्का करें कि अलग-अलग डिसप्ले साइज़ के लिए पूरा डेटा उपलब्ध हो

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

हालांकि, ऐसा करने से डेटा के एकतरफ़ा फ़्लो के सिद्धांत का उल्लंघन होता है. इस सिद्धांत के तहत, डेटा को होस्ट किया जा सकता है और सही तरीके से रेंडर करने के लिए, कॉम्पोज़ेबल को उपलब्ध कराया जा सकता है. कॉम्पोज़ेबल में ज़रूरत के मुताबिक डेटा होना चाहिए, ताकि कॉम्पोज़ेबल में किसी भी डिसप्ले साइज़ के लिए हमेशा ज़रूरत के मुताबिक कॉन्टेंट हो. भले ही, कॉन्टेंट के कुछ हिस्से का इस्तेमाल हमेशा न किया जाए.

@Composable
fun Card(
    imageUrl: String,
    title: String,
    description: String
) {
    BoxWithConstraints {
        if (maxWidth < 400.dp) {
            Column {
                Image(imageUrl)
                Title(title)
            }
        } else {
            Row {
                Column {
                    Title(title)
                    Description(description)
                }
                Image(imageUrl)
            }
        }
    }
}

Card के उदाहरण के आधार पर, ध्यान दें कि description हमेशा Card को पास किया जाता है. description का इस्तेमाल सिर्फ़ तब किया जाता है, जब चौड़ाई की वजह से इसे दिखाया जा सकता हो. हालांकि, Card के लिए description का इस्तेमाल करना ज़रूरी है. भले ही, उपलब्ध चौड़ाई कुछ भी हो.

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

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

@Composable
fun Card(
    imageUrl: String,
    title: String,
    description: String
) {
    var showMore by remember { mutableStateOf(false) }

    BoxWithConstraints {
        if (maxWidth < 400.dp) {
            Column {
                Image(imageUrl)
                Title(title)
            }
        } else {
            Row {
                Column {
                    Title(title)
                    Description(
                        description = description,
                        showMore = showMore,
                        onShowMoreToggled = { newValue ->
                            showMore = newValue
                        }
                    )
                }
                Image(imageUrl)
            }
        }
    }
}

ज़्यादा जानें

Compose में अडैप्टिव लेआउट के बारे में ज़्यादा जानने के लिए, यहां दिए गए रिसॉर्स देखें:

ऐप्लिकेशन के सैंपल

  • CanonicalLayouts एक ऐसा रिपॉज़िटरी है जिसमें ऐसे डिज़ाइन पैटर्न मौजूद हैं जो बड़े डिसप्ले पर उपयोगकर्ताओं को बेहतर अनुभव देते हैं
  • JetNews में, ऐसे ऐप्लिकेशन को डिज़ाइन करने का तरीका बताया गया है जो डिसप्ले के उपलब्ध स्पेस का इस्तेमाल करने के लिए, अपने यूज़र इंटरफ़ेस में बदलाव करता है
  • Reply एक अडैप्टिव सैंपल है, जो मोबाइल, टैबलेट, और फ़ोल्ड किए जा सकने वाले डिवाइसों पर काम करता है
  • Now in Android एक ऐसा ऐप्लिकेशन है जो अलग-अलग डिसप्ले साइज़ के साथ काम करने के लिए, अडैप्टिव लेआउट का इस्तेमाल करता है

वीडियो