1. परिचय
इस कोडलैब में, आपको फ़ोन, टैबलेट, और फ़ोल्ड किए जा सकने वाले डिवाइसों के लिए अडैप्टिव ऐप्लिकेशन बनाने का तरीका बताया जाएगा. साथ ही, यह भी बताया जाएगा कि Jetpack Compose की मदद से, इन ऐप्लिकेशन की पहुंच कैसे बढ़ाई जा सकती है. आपको Material 3 कॉम्पोनेंट और थीमिंग का इस्तेमाल करने के सबसे सही तरीकों के बारे में भी जानकारी मिलेगी.
आगे बढ़ने से पहले, यह समझना ज़रूरी है कि हम अडैप्टेबिलिटी से क्या समझते हैं.
ज़रूरत के हिसाब से बदलाव करने की सुविधा
आपके ऐप्लिकेशन का यूज़र इंटरफ़ेस (यूआई) रिस्पॉन्सिव होना चाहिए, ताकि वह अलग-अलग विंडो साइज़, ओरिएंटेशन, और फ़ॉर्म फ़ैक्टर के हिसाब से काम कर सके. अडैप्टिव लेआउट, स्क्रीन के लिए उपलब्ध जगह के हिसाब से बदलता है. इन बदलावों में, लेआउट को अडजस्ट करके जगह को भरना, नेविगेशन की स्टाइल चुनना, और ज़्यादा जगह का इस्तेमाल करने के लिए लेआउट को पूरी तरह से बदलना शामिल है.
ज़्यादा जानने के लिए, ऐडैप्टिव डिज़ाइन देखें.
इस कोडलैब में, Jetpack Compose का इस्तेमाल करते समय अडैप्टेबिलिटी का इस्तेमाल करने और इसके बारे में सोचने का तरीका बताया गया है. आपने Reply नाम का एक ऐप्लिकेशन बनाया है. इसमें बताया गया है कि सभी तरह की स्क्रीन के लिए, अडैप्टेबिलिटी को कैसे लागू किया जाए. साथ ही, यह भी बताया गया है कि अडैप्टेबिलिटी और पहुंच से जुड़ी सुविधाएं, उपयोगकर्ताओं को बेहतर अनुभव देने के लिए एक साथ कैसे काम करती हैं.
आपको क्या सीखने को मिलेगा
- Jetpack Compose की मदद से, सभी विंडो साइज़ को टारगेट करने के लिए अपने ऐप्लिकेशन को डिज़ाइन करने का तरीका.
- अलग-अलग फ़ोल्ड किए जा सकने वाले डिवाइसों के लिए, अपने ऐप्लिकेशन को कैसे टारगेट करें.
- बेहतर पहुंच और सुलभता के लिए, अलग-अलग तरह के नेविगेशन का इस्तेमाल कैसे करें.
- हर विंडो साइज़ के लिए सबसे अच्छा अनुभव देने के लिए, Material 3 कॉम्पोनेंट का इस्तेमाल कैसे करें.
आपको किन चीज़ों की ज़रूरत होगी
- Android Studio का नया स्टेबल वर्शन.
- Android 13 का ऐसा वर्चुअल डिवाइस जिसका साइज़ बदला जा सकता हो.
- Kotlin की जानकारी.
- Compose की बुनियादी जानकारी (जैसे,
@Composableएनोटेशन). - Compose लेआउट (जैसे,
RowऔरColumn) के बारे में बुनियादी जानकारी. - मॉडिफ़ायर (जैसे,
Modifier.padding()) के बारे में बुनियादी जानकारी.
इस कोडलैब के लिए, रीसाइज़ किए जा सकने वाले एम्युलेटर का इस्तेमाल किया जाएगा. इससे अलग-अलग तरह के डिवाइसों और विंडो के साइज़ के बीच स्विच किया जा सकता है.

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

2. सेट अप करें
इस कोडलैब के लिए कोड पाने के लिए, कमांड लाइन से GitHub रिपॉज़िटरी को क्लोन करें:
git clone https://github.com/android/codelab-android-compose.git cd codelab-android-compose/AdaptiveUiCodelab
इसके अलावा, रिपॉज़िटरी को ZIP फ़ाइल के तौर पर डाउनलोड किया जा सकता है:
हमारा सुझाव है कि आप main ब्रांच में मौजूद कोड से शुरुआत करें. साथ ही, कोडलैब में दिए गए निर्देशों को अपनी सुविधा के हिसाब से एक-एक करके पूरा करें.
Android Studio में प्रोजेक्ट खोलना
- Android Studio में आपका स्वागत है विंडो में,
कोई मौजूदा प्रोजेक्ट खोलें को चुनें. - फ़ोल्डर
<Download Location>/AdaptiveUiCodelabको चुनें. पक्का करें कि आपनेbuild.gradleवालीAdaptiveUiCodelabडायरेक्ट्री को चुना हो. - Android Studio में प्रोजेक्ट इंपोर्ट हो जाने के बाद, जांच करें कि
mainब्रांच को चलाया जा सकता है या नहीं.
स्टार्ट कोड एक्सप्लोर करना
main ब्रांच कोड में ui पैकेज होता है. आपको उस पैकेज में मौजूद इन फ़ाइलों के साथ काम करना होगा:
MainActivity.kt- एंट्री पॉइंट गतिविधि, जहां से ऐप्लिकेशन शुरू किया जाता है.ReplyApp.kt- इसमें मुख्य स्क्रीन के यूज़र इंटरफ़ेस (यूआई) के कंपोज़ेबल शामिल हैं.ReplyHomeViewModel.kt- यह ऐप्लिकेशन के कॉन्टेंट के लिए डेटा और यूज़र इंटरफ़ेस (यूआई) की स्थिति की जानकारी देता है.ReplyListContent.kt- इसमें सूचियां और जानकारी वाली स्क्रीन उपलब्ध कराने के लिए कंपोज़ेबल शामिल होते हैं.
अगर इस ऐप्लिकेशन को साइज़ बदलने वाले एम्युलेटर पर चलाया जाता है और अलग-अलग तरह के डिवाइसों, जैसे कि फ़ोन या टैबलेट पर आज़माया जाता है, तो यूज़र इंटरफ़ेस (यूआई) सिर्फ़ दी गई जगह के हिसाब से बड़ा हो जाता है. यह स्क्रीन स्पेस का फ़ायदा नहीं उठाता या पहुंच के लिए एर्गोनॉमिक्स उपलब्ध नहीं कराता.


आपको इसे अपडेट करना होगा, ताकि स्क्रीन स्पेस का फ़ायदा उठाया जा सके, इसे इस्तेमाल करना आसान हो, और उपयोगकर्ता अनुभव को बेहतर बनाया जा सके.
3. ऐप्लिकेशन को अडैप्टिव बनाना
इस सेक्शन में बताया गया है कि ऐप्लिकेशन को अडैप्टिव बनाने का क्या मतलब है. साथ ही, यह भी बताया गया है कि Material 3, ऐप्लिकेशन को अडैप्टिव बनाने के लिए कौनसे कॉम्पोनेंट उपलब्ध कराता है. इसमें उन स्क्रीन और स्थितियों के बारे में भी बताया गया है जिन्हें आपको टारगेट करना है. जैसे, फ़ोन, टैबलेट, बड़े टैबलेट, और फ़ोल्ड किए जा सकने वाले डिवाइस.
इस कोर्स में, आपको विंडो के साइज़, फ़ोल्ड करने की स्थितियों, और नेविगेशन के अलग-अलग विकल्पों के बारे में बुनियादी जानकारी मिलेगी. इसके बाद, अपने ऐप्लिकेशन में इन एपीआई का इस्तेमाल करके, उसे ज़्यादा अडैप्टिव बनाया जा सकता है.
विंडो के साइज़
Android डिवाइस कई तरह के होते हैं. जैसे, फ़ोन, फ़ोल्ड किए जा सकने वाले डिवाइस, टैबलेट, और ChromeOS डिवाइस. ज़्यादा से ज़्यादा विंडो साइज़ के साथ काम करने के लिए, आपके यूज़र इंटरफ़ेस (यूआई) को रिस्पॉन्सिव और अडैप्टिव होना चाहिए. हमने ब्रेकपॉइंट वैल्यू तय की हैं. इनकी मदद से, यह तय किया जा सकता है कि आपके ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई) को किस थ्रेशोल्ड पर बदलना है. इन वैल्यू की मदद से, डिवाइसों को पहले से तय की गई साइज़ क्लास (कंपैक्ट, मीडियम, और बड़ा) में बांटा जाता है. इन्हें विंडो साइज़ क्लास कहा जाता है. ये व्यूपोर्ट ब्रेकपॉइंट का एक सेट है. इनकी मदद से, रिस्पॉन्सिव और अडैप्टिव ऐप्लिकेशन लेआउट को डिज़ाइन, डेवलप, और टेस्ट किया जा सकता है.
इन कैटगरी को खास तौर पर इसलिए चुना गया है, ताकि लेआउट को आसान बनाया जा सके. साथ ही, खास मामलों के लिए अपने ऐप्लिकेशन को ऑप्टिमाइज़ करने की सुविधा भी दी जा सके. विंडो के साइज़ क्लास का पता हमेशा ऐप्लिकेशन के लिए उपलब्ध स्क्रीन स्पेस से चलता है. यह मल्टीटास्किंग या अन्य सेगमेंटेशन के लिए, पूरी फ़िज़िकल स्क्रीन नहीं हो सकती.


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

इसके अलावा, हो सकता है कि उपयोगकर्ता ने फ़ोन को थोड़ा खोलकर, अंदर की डिसप्ले को देखा हो. इससे, फ़ोन को फ़ोल्ड करने के तरीके के आधार पर, उपयोगकर्ता की शारीरिक मुद्रा अलग-अलग हो सकती है: टेबलटॉप मुद्रा (हॉरिजॉन्टल फ़ोल्ड, ऊपर दी गई इमेज में दाईं ओर दिखाया गया है) और किताब की मुद्रा (वर्टिकल फ़ोल्ड).
फ़ोल्ड करने की स्थितियों और हिंज के बारे में ज़्यादा जानें.
फ़ोल्ड किए जा सकने वाले डिवाइसों के लिए अडैप्टिव लेआउट लागू करते समय, इन सभी बातों का ध्यान रखना ज़रूरी है.
ज़रूरत के हिसाब से जानकारी पाना
Material3 adaptive लाइब्रेरी, आपके ऐप्लिकेशन के चालू होने की विंडो के बारे में जानकारी को आसानी से ऐक्सेस करने की सुविधा देती है.
- वर्शन कैटलॉग फ़ाइल में, इस आर्टफ़ैक्ट और इसके वर्शन के लिए एंट्री जोड़ें:
gradle/libs.versions.toml
[versions]
material3Adaptive = "1.0.0"
[libraries]
androidx-material3-adaptive = { module = "androidx.compose.material3.adaptive:adaptive", version.ref = "material3Adaptive" }
- ऐप्लिकेशन मॉड्यूल की build फ़ाइल में, नई लाइब्रेरी डिपेंडेंसी जोड़ें. इसके बाद, Gradle सिंक करें:
app/build.gradle.kts
dependencies {
implementation(libs.androidx.material3.adaptive)
}
अब किसी भी कंपोज़ेबल स्कोप में, currentWindowAdaptiveInfo() का इस्तेमाल करके WindowAdaptiveInfo ऑब्जेक्ट पाया जा सकता है. इसमें मौजूदा विंडो के साइज़ क्लास और डिवाइस के फ़ोल्ड होने की स्थिति (जैसे, टेबलटॉप मोड) जैसी जानकारी शामिल होती है.
अब MainActivity में जाकर, इसे आज़माएं.
ReplyThemeब्लॉक के अंदर मौजूदonCreate()में, विंडो के अडैप्टिव होने की जानकारी पाएं. साथ ही, साइज़ क्लास कोTextकंपोज़ेबल में दिखाएं. इसेReplyApp()एलिमेंट के बाद जोड़ा जा सकता है:
MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ReplyTheme {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
ReplyApp(
replyHomeUIState = uiState,
onEmailClick = viewModel::setSelectedEmail
)
val adaptiveInfo = currentWindowAdaptiveInfo()
val sizeClassText =
"${adaptiveInfo.windowSizeClass.windowWidthSizeClass}\n" +
"${adaptiveInfo.windowSizeClass.windowHeightSizeClass}"
Text(
text = sizeClassText,
color = Color.Magenta,
modifier = Modifier.padding(
WindowInsets.safeDrawing.asPaddingValues()
)
)
}
}
}
अब ऐप्लिकेशन चलाने पर, ऐप्लिकेशन के कॉन्टेंट के ऊपर विंडो साइज़ क्लास प्रिंट किए हुए दिखेंगे. विंडो के हिसाब से ढलने वाली जानकारी में और क्या-क्या दिया गया है, इसके बारे में जानें. इसके बाद, इस Text को हटाया जा सकता है, क्योंकि इसमें ऐप्लिकेशन का कॉन्टेंट शामिल होता है. साथ ही, अगले चरणों के लिए इसकी ज़रूरत नहीं होगी.
4. डाइनैमिक नेविगेशन
अब आपको डिवाइस की स्थिति और साइज़ में बदलाव होने पर, ऐप्लिकेशन के नेविगेशन को अडैप्ट करना होगा, ताकि आपके ऐप्लिकेशन को इस्तेमाल करना आसान हो.
जब उपयोगकर्ता फ़ोन को पकड़ते हैं, तब उनकी उंगलियां आम तौर पर स्क्रीन के सबसे नीचे होती हैं. जब उपयोगकर्ता, खुले हुए फ़ोल्ड किए जा सकने वाले डिवाइस या टैबलेट को पकड़ते हैं, तो उनकी उंगलियां आम तौर पर किनारों के पास होती हैं. आपके ऐप्लिकेशन के उपयोगकर्ताओं को, हाथ की असामान्य स्थिति में रखे बिना या हाथ की जगह बदले बिना, ऐप्लिकेशन में नेविगेट करने या उसके साथ इंटरैक्ट करने की सुविधा मिलनी चाहिए.
ऐप्लिकेशन डिज़ाइन करते समय और लेआउट में इंटरैक्टिव यूज़र इंटरफ़ेस (यूआई) एलिमेंट को रखने का फ़ैसला करते समय, स्क्रीन के अलग-अलग हिस्सों के एर्गोनॉमिक असर के बारे में सोचें.
- डिवाइस को पकड़ते समय, किन जगहों पर आसानी से पहुंचा जा सकता है?
- किन जगहों पर पहुंचने के लिए, सिर्फ़ उंगलियों को फैलाया जा सकता है. इससे शायद आपको परेशानी हो.
- कौनसे ऐसे इलाके हैं जहां पहुंचना मुश्किल है या जो उपयोगकर्ता के डिवाइस से दूर हैं?
नेविगेशन, वह पहला एलिमेंट होता है जिससे उपयोगकर्ता इंटरैक्ट करते हैं. इसमें उपयोगकर्ता के अहम सफ़र से जुड़ी ज़रूरी कार्रवाइयां शामिल होती हैं. इसलिए, इसे उन जगहों पर रखा जाना चाहिए जहां इसे आसानी से ऐक्सेस किया जा सके. मटीरियल अडैप्टिव लाइब्रेरी में कई कॉम्पोनेंट होते हैं. ये कॉम्पोनेंट, डिवाइस की विंडो के साइज़ के हिसाब से नेविगेशन लागू करने में आपकी मदद करते हैं.
बॉटम नेविगेशन
बॉटम नेविगेशन, छोटे साइज़ के डिवाइसों के लिए सबसे सही होता है. ऐसा इसलिए, क्योंकि हम डिवाइस को इस तरह से पकड़ते हैं कि हमारा अंगूठा, बॉटम नेविगेशन के सभी टच पॉइंट तक आसानी से पहुंच सके. इसका इस्तेमाल तब करें, जब आपके पास छोटा डिवाइस हो या फ़ोल्ड किए गए छोटे डिवाइस का इस्तेमाल करना हो.

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

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

हमेशा दिखने वाला नेविगेशन पैनल
बड़े टैबलेट, Chromebook, और डेस्कटॉप पर नेविगेशन को एक जगह पर सेट करने के लिए, परमानेंट नेविगेशन ड्रॉअर का इस्तेमाल किया जा सकता है.

डाइनैमिक नेविगेशन लागू करना
अब डिवाइस की स्थिति और साइज़ में बदलाव होने पर, नेविगेशन के अलग-अलग टाइप के बीच स्विच किया जा सकेगा.
फ़िलहाल, ऐप्लिकेशन में स्क्रीन के कॉन्टेंट के नीचे हमेशा NavigationBar दिखता है. भले ही, डिवाइस की स्थिति कुछ भी हो. इसके बजाय, Material NavigationSuiteScaffold कॉम्पोनेंट का इस्तेमाल किया जा सकता है. इससे, मौजूदा विंडो साइज़ क्लास जैसी जानकारी के आधार पर, अलग-अलग नेविगेशन कॉम्पोनेंट के बीच अपने-आप स्विच किया जा सकता है.
- इस कॉम्पोनेंट को पाने के लिए, Gradle डिपेंडेंसी जोड़ें. इसके लिए, वर्शन कैटलॉग और ऐप्लिकेशन की बिल्ड स्क्रिप्ट को अपडेट करें. इसके बाद, Gradle सिंक करें:
gradle/libs.versions.toml
[versions]
material3AdaptiveNavSuite = "1.3.0"
[libraries]
androidx-material3-adaptive-navigation-suite = { module = "androidx.compose.material3:material3-adaptive-navigation-suite", version.ref = "material3AdaptiveNavSuite" }
app/build.gradle.kts
dependencies {
implementation(libs.androidx.material3.adaptive.navigation.suite)
}
ReplyApp.ktमेंReplyNavigationWrapper()कंपोज़ेबल फ़ंक्शन ढूंढें. इसके बाद,Columnऔर उसके कॉन्टेंट कोNavigationSuiteScaffoldसे बदलें:
ReplyApp.kt
@Composable
private fun ReplyNavigationWrapperUI(
content: @Composable () -> Unit = {}
) {
var selectedDestination: ReplyDestination by remember {
mutableStateOf(ReplyDestination.Inbox)
}
NavigationSuiteScaffold(
navigationSuiteItems = {
ReplyDestination.entries.forEach {
item(
selected = it == selectedDestination,
onClick = { /*TODO update selection*/ },
icon = {
Icon(
imageVector = it.icon,
contentDescription = stringResource(it.labelRes)
)
},
label = {
Text(text = stringResource(it.labelRes))
},
)
}
}
) {
content()
}
}
navigationSuiteItems आर्ग्युमेंट एक ऐसा ब्लॉक होता है जिसकी मदद से, item() फ़ंक्शन का इस्तेमाल करके आइटम जोड़े जा सकते हैं. यह LazyColumn में आइटम जोड़ने जैसा होता है. ट्रेलिंग लैंबडा के अंदर, यह कोड content() को कॉल करता है. इसे ReplyNavigationWrapperUI() को आर्ग्युमेंट के तौर पर पास किया जाता है.
ऐप्लिकेशन को एम्युलेटर पर चलाएं. इसके बाद, फ़ोन, फ़ोल्ड किए जा सकने वाले डिवाइस, और टैबलेट के बीच साइज़ बदलें. आपको दिखेगा कि नेविगेशन बार, नेविगेशन रेल में बदल गया है और फिर से नेविगेशन बार में बदल गया है.
बहुत चौड़ी विंडो पर, जैसे कि लैंडस्केप मोड में टैबलेट पर, आपको परमानेंट नेविगेशन ड्रॉअर दिखाना पड़ सकता है. NavigationSuiteScaffold में परमानेंट ड्रॉअर दिखाने की सुविधा है. हालांकि, यह सुविधा WindowWidthSizeClass की किसी भी मौजूदा वैल्यू में नहीं दिखती. हालांकि, इसमें थोड़ा बदलाव करके ऐसा किया जा सकता है.
NavigationSuiteScaffoldको कॉल करने से ठीक पहले, यह कोड जोड़ें:
ReplyApp.kt
@Composable
private fun ReplyNavigationWrapperUI(
content: @Composable () -> Unit = {}
) {
var selectedDestination: ReplyDestination by remember {
mutableStateOf(ReplyDestination.Inbox)
}
val windowSize = with(LocalDensity.current) {
currentWindowSize().toSize().toDpSize()
}
val layoutType = if (windowSize.width >= 1200.dp) {
NavigationSuiteType.NavigationDrawer
} else {
NavigationSuiteScaffoldDefaults.calculateFromAdaptiveInfo(
currentWindowAdaptiveInfo()
)
}
NavigationSuiteScaffold(
layoutType = layoutType,
...
) {
content()
}
}
यह कोड सबसे पहले विंडो का साइज़ पता करता है. इसके बाद, currentWindowSize() और LocalDensity.current का इस्तेमाल करके, इसे डीपी यूनिट में बदलता है. इसके बाद, नेविगेशन यूज़र इंटरफ़ेस (यूआई) के लेआउट टाइप का फ़ैसला करने के लिए, विंडो की चौड़ाई की तुलना करता है. अगर विंडो की चौड़ाई कम से कम 1200.dp है, तो यह NavigationSuiteType.NavigationDrawer का इस्तेमाल करता है. अगर ऐसा नहीं होता है, तो यह डिफ़ॉल्ट कैलकुलेशन पर वापस आ जाता है.
जब आप अपने साइज़ बदलने वाले एम्युलेटर पर ऐप्लिकेशन को फिर से चलाते हैं और अलग-अलग टाइप आज़माते हैं, तो ध्यान दें कि स्क्रीन कॉन्फ़िगरेशन बदलने या फ़ोल्ड किए जा सकने वाले डिवाइस को खोलने पर, नेविगेशन उस साइज़ के हिसाब से सही टाइप में बदल जाता है.

बधाई हो! आपने अलग-अलग तरह की विंडो के साइज़ और स्थितियों के साथ काम करने वाले अलग-अलग तरह के नेविगेशन के बारे में जान लिया है!
अगले सेक्शन में, आपको यह पता चलेगा कि एक ही सूची आइटम को एक किनारे से दूसरे किनारे तक खींचने के बजाय, स्क्रीन के बाकी हिस्से का इस्तेमाल कैसे किया जा सकता है.
5. स्क्रीन स्पेस का इस्तेमाल
चाहे ऐप्लिकेशन को छोटे टैबलेट, अनफ़ोल्ड किए गए डिवाइस या बड़े टैबलेट पर चलाया जा रहा हो, स्क्रीन को स्ट्रेच करके बाकी जगह को भर दिया जाता है. आपको यह पक्का करना होगा कि स्क्रीन पर मौजूद जगह का इस्तेमाल ज़्यादा जानकारी दिखाने के लिए किया जा सके. जैसे, इस ऐप्लिकेशन के लिए, एक ही पेज पर लोगों को ईमेल और थ्रेड दिखाना.
Material 3 में तीन कैननिकल लेआउट तय किए गए हैं. हर लेआउट में, कॉम्पैक्ट, मीडियम, और बड़ी विंडो साइज़ क्लास के लिए कॉन्फ़िगरेशन होते हैं. इस इस्तेमाल के उदाहरण के लिए, लिस्ट डिटेल कैननिकल लेआउट सबसे सही है. यह कंपोज़ में ListDetailPaneScaffold के तौर पर उपलब्ध है.
- यह कॉम्पोनेंट पाने के लिए, ये डिपेंडेंसी जोड़ें और Gradle सिंक करें:
gradle/libs.versions.toml
[libraries]
androidx-material3-adaptive-layout = { module = "androidx.compose.material3.adaptive:adaptive-layout", version.ref = "material3Adaptive" }
androidx-material3-adaptive-navigation = { module = "androidx.compose.material3.adaptive:adaptive-navigation", version.ref = "material3Adaptive" }
app/build.gradle.kts
dependencies {
implementation(libs.androidx.material3.adaptive.layout)
implementation(libs.androidx.material3.adaptive.navigation)
}
ReplyApp.ktमेंReplyAppContent()कंपोज़ेबल फ़ंक्शन ढूंढें. फ़िलहाल, यह सिर्फ़ReplyListPane()को कॉल करके सूची वाला पैन दिखाता है. इस कोड कोListDetailPaneScaffoldसे बदलें. इसके लिए, यह कोड डालें. यह एक एक्सपेरिमेंटल एपीआई है. इसलिए, आपकोReplyAppContent()फ़ंक्शन पर@OptInएनोटेशन भी जोड़ना होगा:
ReplyApp.kt
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
fun ReplyAppContent(
replyHomeUIState: ReplyHomeUIState,
onEmailClick: (Email) -> Unit,
) {
val navigator = rememberListDetailPaneScaffoldNavigator<Long>()
ListDetailPaneScaffold(
directive = navigator.scaffoldDirective,
value = navigator.scaffoldValue,
listPane = {
ReplyListPane(replyHomeUIState, onEmailClick)
},
detailPane = {
ReplyDetailPane(replyHomeUIState.emails.first())
}
)
}
यह कोड, सबसे पहले rememberListDetailPaneNavigator का इस्तेमाल करके नेविगेटर बनाता है. नेविगेटर की मदद से, यह कंट्रोल किया जा सकता है कि कौनसी विंडो दिखेगी और उस विंडो में कौनसा कॉन्टेंट दिखेगा. इसके बारे में बाद में बताया जाएगा.
विंडो की चौड़ाई की साइज़ क्लास को बड़ा करने पर, ListDetailPaneScaffold में दो पैन दिखेंगे. अगर ऐसा नहीं है, तो यह दो पैरामीटर के लिए दी गई वैल्यू के आधार पर, एक या दूसरा पैन दिखाएगा: स्कैफ़ोल्ड डायरेक्टिव और स्कैफ़ोल्ड वैल्यू. डिफ़ॉल्ट व्यवहार पाने के लिए, यह कोड Scaffold डायरेक्टिव और नेविगेटर से मिली Scaffold वैल्यू का इस्तेमाल करता है.
बचे हुए ज़रूरी पैरामीटर, पैन के लिए कंपोज़ेबल लैम्डा हैं. ReplyListPane() और ReplyDetailPane() (ReplyListContent.kt में मौजूद) का इस्तेमाल, सूची और जानकारी वाले पैन की भूमिकाओं को भरने के लिए किया जाता है. ReplyDetailPane() को ईमेल आर्ग्युमेंट की ज़रूरत होती है. इसलिए, फ़िलहाल यह कोड ReplyHomeUIState में मौजूद ईमेल की सूची से पहले ईमेल का इस्तेमाल करता है.
ऐप्लिकेशन चलाएं और एम्युलेटर व्यू को फ़ोल्ड किए जा सकने वाले डिवाइस या टैबलेट पर स्विच करें. दो पैनल वाला लेआउट देखने के लिए, आपको ओरिएंटेशन भी बदलना पड़ सकता है. यह पहले से काफ़ी बेहतर लग रहा है!
अब इस स्क्रीन के कुछ ज़रूरी फ़ंक्शन के बारे में जानते हैं. जब कोई उपयोगकर्ता सूची वाले पैनल में किसी ईमेल पर टैप करता है, तो उसे जवाबों के साथ जानकारी वाले पैनल में दिखना चाहिए. फ़िलहाल, ऐप्लिकेशन यह ट्रैक नहीं करता कि कौनसे ईमेल को चुना गया था. साथ ही, किसी आइटम पर टैप करने से कुछ नहीं होता. इस जानकारी को ReplyHomeUIState में यूज़र इंटरफ़ेस (यूआई) की बाकी स्थिति के साथ रखना सबसे सही होता है.
ReplyHomeViewModel.ktखोलें औरReplyHomeUIStateडेटा क्लास ढूंढें. चुने गए ईमेल के लिए एक प्रॉपर्टी जोड़ें. इसकी डिफ़ॉल्ट वैल्यूnullहै:
ReplyHomeViewModel.kt
data class ReplyHomeUIState(
val emails : List<Email> = emptyList(),
val selectedEmail: Email? = null,
val loading: Boolean = false,
val error: String? = null
)
- इसी फ़ाइल में,
ReplyHomeViewModelमें एकsetSelectedEmail()फ़ंक्शन होता है. जब उपयोगकर्ता किसी सूची आइटम पर टैप करता है, तब इस फ़ंक्शन को कॉल किया जाता है. यूज़र इंटरफ़ेस (यूआई) की स्थिति को कॉपी करने और चुने गए ईमेल को रिकॉर्ड करने के लिए, इस फ़ंक्शन में बदलाव करें:
ReplyHomeViewModel.kt
fun setSelectedEmail(email: Email) {
_uiState.update {
it.copy(selectedEmail = email)
}
}
यह ध्यान रखना ज़रूरी है कि जब उपयोगकर्ता किसी आइटम पर टैप नहीं करता है और चुना गया ईमेल null होता है, तो क्या होता है. ज़्यादा जानकारी वाले पैनल में क्या दिखना चाहिए? इस मामले को हैंडल करने के कई तरीके हैं. जैसे, सूची में मौजूद पहले आइटम को डिफ़ॉल्ट रूप से दिखाना.
- उसी फ़ाइल में,
observeEmails()फ़ंक्शन में बदलाव करें. ईमेल की सूची लोड होने पर, अगर पिछली यूज़र इंटरफ़ेस (यूआई) स्थिति में कोई ईमेल नहीं चुना गया था, तो उसे पहले आइटम पर सेट करें:
ReplyHomeViewModel.kt
private fun observeEmails() {
viewModelScope.launch {
emailsRepository.getAllEmails()
.catch { ex ->
_uiState.value = ReplyHomeUIState(error = ex.message)
}
.collect { emails ->
val currentSelection = _uiState.value.selectedEmail
_uiState.value = ReplyHomeUIState(
emails = emails,
selectedEmail = currentSelection ?: emails.first()
)
}
}
}
ReplyApp.ktपर वापस जाएं. अगर चुना गया ईमेल उपलब्ध है, तो उसका इस्तेमाल करके ज़्यादा जानकारी वाले पैनल में कॉन्टेंट भरें:
ReplyApp.kt
ListDetailPaneScaffold(
// ...
detailPane = {
if (replyHomeUIState.selectedEmail != null) {
ReplyDetailPane(replyHomeUIState.selectedEmail)
}
}
)
ऐप्लिकेशन को फिर से चलाएं और एम्युलेटर को टैबलेट के साइज़ पर स्विच करें. देखें कि सूची के किसी आइटम पर टैप करने से, जानकारी वाले पैनल का कॉन्टेंट अपडेट हो जाता है.
जब दोनों पैन दिखते हैं, तब यह सुविधा ठीक से काम करती है. हालांकि, जब विंडो में सिर्फ़ एक पैन दिखता है, तो किसी आइटम पर टैप करने पर ऐसा लगता है कि कुछ नहीं हुआ. एम्युलेटर व्यू को फ़ोन या पोर्ट्रेट मोड में फ़ोल्ड किए जा सकने वाले डिवाइस पर स्विच करके देखें. साथ ही, ध्यान दें कि किसी आइटम पर टैप करने के बाद भी, सिर्फ़ सूची वाला पैन दिखता है. ऐसा इसलिए होता है, क्योंकि चुने गए ईमेल को अपडेट करने के बावजूद, ListDetailPaneScaffold इन कॉन्फ़िगरेशन में सूची वाले पैनल पर फ़ोकस बनाए रखता है.
- इसे ठीक करने के लिए,
ReplyListPaneमें पास किए गए लैम्ब्डा के तौर पर यह कोड डालें:
ReplyApp.kt
ListDetailPaneScaffold(
// ...
listPane = {
ReplyListPane(
replyHomeUIState = replyHomeUIState,
onEmailClick = { email ->
onEmailClick(email)
navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, email.id)
}
)
},
// ...
)
यह लैंबडा, पहले बनाए गए नेविगेटर का इस्तेमाल करता है. इससे किसी आइटम पर क्लिक करने पर, अतिरिक्त व्यवहार जोड़ा जा सकता है. यह फ़ंक्शन, इस फ़ंक्शन को पास किए गए ओरिजनल लैम्डा को कॉल करेगा. इसके बाद, यह navigator.navigateTo() को भी कॉल करेगा. इससे यह तय किया जा सकेगा कि कौनसा पैनल दिखाया जाना चाहिए. स्काफ़ोल्ड में मौजूद हर पैन की एक भूमिका होती है. जानकारी वाले पैन के लिए, यह भूमिका ListDetailPaneScaffoldRole.Detail होती है. छोटी विंडो पर, इससे ऐसा लगेगा कि ऐप्लिकेशन आगे बढ़ गया है.
ऐप्लिकेशन को यह भी मैनेज करना होगा कि जब उपयोगकर्ता, ज़्यादा जानकारी वाले पैनल से 'वापस जाएं' बटन दबाता है, तो क्या होता है. यह व्यवहार इस बात पर निर्भर करेगा कि एक पैनल दिख रहा है या दो पैनल दिख रहे हैं.
- यहां दिया गया कोड जोड़कर, वापस जाने की सुविधा चालू करें.
ReplyApp.kt
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
@Composable
fun ReplyAppContent(
replyHomeUIState: ReplyHomeUIState,
onEmailClick: (Email) -> Unit,
) {
val navigator = rememberListDetailPaneScaffoldNavigator<Long>()
BackHandler(navigator.canNavigateBack()) {
navigator.navigateBack()
}
ListDetailPaneScaffold(
directive = navigator.scaffoldDirective,
value = navigator.scaffoldValue,
listPane = {
AnimatedPane {
ReplyListPane(
replyHomeUIState = replyHomeUIState,
onEmailClick = { email ->
onEmailClick(email)
navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, email.id)
}
)
}
},
detailPane = {
AnimatedPane {
if (replyHomeUIState.selectedEmail != null) {
ReplyDetailPane(replyHomeUIState.selectedEmail)
}
}
}
)
}
नेविगेटर को ListDetailPaneScaffold की पूरी स्थिति के बारे में पता होता है. जैसे, बैक नेविगेशन की सुविधा उपलब्ध है या नहीं और इन सभी स्थितियों में क्या करना है. यह कोड एक BackHandler बनाता है. यह तब चालू होता है, जब नेविगेटर वापस जा सकता है. साथ ही, लैंबडा के अंदर navigateBack() को कॉल करता है. साथ ही, पैन के बीच ट्रांज़िशन को ज़्यादा आसान बनाने के लिए, हर पैन को AnimatedPane() कंपोज़ेबल में रैप किया जाता है.
सभी तरह के डिवाइसों के लिए, साइज़ बदलने वाले एम्युलेटर पर ऐप्लिकेशन को फिर से चलाएं. ध्यान दें कि जब भी स्क्रीन कॉन्फ़िगरेशन बदलता है या फ़ोल्ड किए जा सकने वाले डिवाइस को अनफ़ोल्ड किया जाता है, तो डिवाइस की स्थिति में होने वाले बदलावों के हिसाब से नेविगेशन और स्क्रीन कॉन्टेंट में अपने-आप बदलाव होता है. इसके अलावा, सूची वाले पैनल में मौजूद ईमेल पर टैप करके देखें कि अलग-अलग स्क्रीन पर लेआउट कैसा दिखता है. इसमें दोनों पैनल साथ-साथ दिखते हैं या उनके बीच आसानी से स्विच किया जा सकता है.

बधाई हो, आपने अपने ऐप्लिकेशन को सभी तरह के डिवाइसों की स्थितियों और साइज़ के हिसाब से अडैप्टिव बना लिया है. अब फ़ोल्ड किए जा सकने वाले डिवाइसों, टैबलेट या अन्य मोबाइल डिवाइसों पर ऐप्लिकेशन चलाकर देखें.
6. बधाई हो
बधाई हो! आपने इस कोडलैब को पूरा कर लिया है. साथ ही, आपने Jetpack Compose की मदद से ऐप्लिकेशन को अडैप्टिव बनाने का तरीका भी सीख लिया है.
आपने किसी डिवाइस के साइज़ और फ़ोल्ड होने की स्थिति की जांच करने का तरीका सीखा. साथ ही, आपने अपने ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई), नेविगेशन, और अन्य फ़ंक्शन को इसके हिसाब से अपडेट करने का तरीका सीखा. आपने यह भी जाना कि अडैप्टेबिलिटी से, पहुंच को कैसे बेहतर बनाया जा सकता है और उपयोगकर्ता अनुभव को कैसे बेहतर बनाया जा सकता है.
आगे क्या करना है?
Compose के पाथवे पर मौजूद अन्य कोडलैब देखें.
सैंपल ऐप्लिकेशन
- Compose के सैंपल, कई ऐप्लिकेशन का कलेक्शन होते हैं. इनमें कोडलैब में बताए गए सबसे सही तरीकों को शामिल किया जाता है.