1. परिचय
इस कोडलैब में, आपको फ़ोन, टैबलेट, और फ़ोल्ड किए जा सकने वाले डिवाइसों के हिसाब से ऐप्लिकेशन बनाने का तरीका बताया गया है. साथ ही, यह भी बताया गया है कि Jetpack Compose की मदद से, ये ऐप्लिकेशन बेहतर ढंग से पहुंच पाते हैं या नहीं. आपको मटीरियल 3 कॉम्पोनेंट और थीमिंग का इस्तेमाल करने के सबसे सही तरीकों के बारे में भी जानकारी मिलेगी.
आगे बढ़ने से पहले, यह समझना ज़रूरी है कि ज़रूरत के हिसाब से ढलने का हमारा मतलब क्या है.
अडैप्टेबिलिटी
आपके ऐप्लिकेशन का यूज़र इंटरफ़ेस (यूआई), अलग-अलग साइज़ की विंडो, स्क्रीन की दिशा, और डिवाइस के नाप या आकार के हिसाब से रिस्पॉन्सिव होना चाहिए. अडैप्टिव लेआउट, स्क्रीन की जगह के हिसाब से बदल जाता है. इन बदलावों में आसान लेआउट अडजस्टमेंट से लेकर जगह को भरने, संबंधित नेविगेशन स्टाइल चुनने, ज़्यादा जगह का इस्तेमाल करने के लिए पूरी तरह से लेआउट बदलने तक की कार्रवाइयां शामिल हैं.
ज़्यादा जानने के लिए, अडैप्टिव डिज़ाइन देखें.
इस कोडलैब में, आपको Jetpack Compose की सुविधा इस्तेमाल करने के बारे में जानकारी मिलेगी. साथ ही, यह बताया गया है कि इसे इस्तेमाल करते समय डिवाइस को ज़रूरत के हिसाब से कैसे इस्तेमाल करना है. आपने 'जवाब दें' नाम का एक ऐप्लिकेशन बनाया है. इसमें यह बताया गया है कि सभी तरह की स्क्रीन के हिसाब से, ज़रूरत के हिसाब से बदलाव करने की सुविधा कैसे लागू की जा सकती है. साथ ही, यह भी पता चलता है कि उपयोगकर्ताओं को बेहतर अनुभव देने के लिए, पर्यावरण को ध्यान में रखकर दी जाने वाली सुविधा और रीचेबिलिटी, एक साथ कैसे काम करती है.
आपको क्या सीखने को मिलेगा
- Jetpack Compose के ज़रिए सभी विंडो को टारगेट करने के लिए अपने ऐप्लिकेशन को कैसे डिज़ाइन करें.
- फ़ोल्ड किए जा सकने वाले अलग-अलग डिवाइसों के लिए अपने ऐप्लिकेशन को टारगेट करने का तरीका.
- सुलभता और आसानी से पहुंचने के लिए, अलग-अलग तरह के नेविगेशन का इस्तेमाल करने का तरीका.
- हर साइज़ की विंडो के लिए बेहतरीन अनुभव देने के लिए, Material 3 कॉम्पोनेंट का इस्तेमाल करने का तरीका.
आपको किन चीज़ों की ज़रूरत होगी
- Android Studio का नया और स्टेबल वर्शन.
- Android 13 वर्शन वाला वर्चुअल डिवाइस, जिसका साइज़ बदला जा सकता है.
- Kotlin के बारे में जानकारी.
- कंपोज़ की बुनियादी जानकारी, जैसे कि
@Composable
से जुड़ा एनोटेशन. - Compose के लेआउट की बुनियादी जानकारी, जैसे कि
Row
औरColumn
. - कार्रवाई बदलने वाली कुंजी के बारे में बुनियादी जानकारी (जैसे,
Modifier.padding()
).
इस कोडलैब के लिए, साइज़ का साइज़ बदलने वाला एम्युलेटर इस्तेमाल किया जा सकता है. इससे आपको अलग-अलग तरह के डिवाइसों और विंडो साइज़ के बीच स्विच करने में मदद मिलती है.
अगर आपको Compose के बारे में नहीं पता है, तो इस कोडलैब को पूरा करने से पहले, Jetpack Compose के बारे में बुनियादी बातें बताने वाला कोडलैब इस्तेमाल करें.
आपको क्या बनाना होगा
- जवाब दें नाम का एक इंटरैक्टिव ईमेल क्लाइंट ऐप्लिकेशन, जिसमें ज़रूरत के हिसाब से डिज़ाइन करने, अलग-अलग मटीरियल नेविगेशन, और स्क्रीन के लिए सबसे सही इस्तेमाल के सबसे सही तरीकों का इस्तेमाल किया गया है.
2. सेट अप करें
इस कोडलैब का कोड पाने के लिए, कमांड लाइन से GitHub रिपॉज़िटरी का क्लोन बनाएं:
git clone https://github.com/android/codelab-android-compose.git cd codelab-android-compose/AdaptiveUiCodelab
इसके अलावा, डेटा स्टोर करने की जगह को ZIP फ़ाइल के तौर पर डाउनलोड किया जा सकता है:
हमारा सुझाव है कि आप मुख्य ब्रांच में कोड से शुरू करें और अपनी रफ़्तार से कोडलैब का सिलसिलेवार तरीके से पालन करें.
प्रोजेक्ट को Android Studio में खोलें
- Android Studio में आपका स्वागत है विंडो में,
मौजूदा प्रोजेक्ट खोलें को चुनें.
- फ़ोल्डर
<Download Location>/AdaptiveUiCodelab
चुनें. पक्का करें कि आपनेAdaptiveUiCodelab
डायरेक्ट्री मेंbuild.gradle
को चुना हो. - Android Studio से प्रोजेक्ट इंपोर्ट हो जाने के बाद, जांच लें कि आपके पास
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-beta01"
[libraries]
androidx-material3-adaptive = { module = "androidx.compose.material3.adaptive:adaptive", version.ref = "material3Adaptive" }
- ऐप्लिकेशन मॉड्यूल की बिल्ड फ़ाइल में, नई लाइब्रेरी डिपेंडेंसी जोड़ें और फिर 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
दिखाता है. भले ही, डिवाइस की स्थिति कुछ भी हो. इसके बजाय, विंडो के मौजूदा साइज़ क्लास जैसी जानकारी के आधार पर, नेविगेशन के अलग-अलग कॉम्पोनेंट के बीच अपने-आप स्विच करने के लिए, मटीरियल NavigationSuiteScaffold
कॉम्पोनेंट का इस्तेमाल किया जा सकता है.
- वर्शन कैटलॉग और ऐप्लिकेशन की बिल्ड स्क्रिप्ट को अपडेट करके, यह कॉम्पोनेंट पाने के लिए Gradle डिपेंडेंसी जोड़ें. इसके बाद, Gradle सिंक करें:
gradle/libs.versions.toml
[versions]
material3AdaptiveNavSuite = "1.3.0-beta01"
[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
में आइटम जोड़ने जैसा ही है. पीछे वाले लैम्डा के अंदर, यह कोड ReplyNavigationWrapperUI()
को तर्क के रूप में पास किए गए content()
को कॉल करता है.
एम्युलेटर पर ऐप्लिकेशन चलाएं और फ़ोन, फ़ोल्ड किए जा सकने वाले डिवाइस, और टैबलेट के बीच साइज़ बदलकर देखें. इसके बाद, आपका नेविगेशन बार दिखेगा, जो नेविगेशन रेल में बदल जाएगा और पीछे हट जाएगा.
बहुत चौड़ी विंडो, जैसे कि लैंडस्केप मोड में टैबलेट पर, हो सकता है कि आप हमेशा के लिए नेविगेशन पैनल दिखाना चाहें. 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. स्क्रीन स्पेस का इस्तेमाल
इस बात से कोई फ़र्क़ नहीं पड़ता कि ऐप्लिकेशन को छोटे टैबलेट, किसी खुले हुए डिवाइस या बड़े टैबलेट पर चलाया जा रहा है. बाकी बची जगह को पूरा करने के लिए स्क्रीन को खींचा गया हो. आपको यह पक्का करना होगा कि आप उस स्क्रीन स्पेस का इस्तेमाल करके, ज़्यादा जानकारी दिखा सकें. जैसे, इस ऐप्लिकेशन के लिए, एक ही पेज पर मौजूद उपयोगकर्ताओं को ईमेल और थ्रेड दिखाना.
मटीरियल 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
दो पैनल दिखाएगा. अगर ऐसा नहीं है, तो यह दो पैरामीटर के लिए दी गई वैल्यू के आधार पर कोई एक पैनल या दूसरा पैनल दिखाएगा: स्कैफ़ोल्ड डायरेक्टिव और स्कैफ़ोल्ड वैल्यू. डिफ़ॉल्ट व्यवहार पाने के लिए, यह कोड स्कैफ़ोल्ड डायरेक्टिव और नेविगेटर से मिली स्केल वैल्यू का इस्तेमाल करता है.
बाकी के ज़रूरी पैरामीटर, पैनल के लिए कंपोज़ेबल लैम्डा हैं. 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
को पास किए गए Lambda फ़ंक्शन के तौर पर यह कोड डालें:
ReplyApp.kt
ListDetailPaneScaffold(
// ...
listPane = {
ReplyListPane(
replyHomeUIState = replyHomeUIState,
onEmailClick = { email ->
onEmailClick(email)
navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, email.id)
}
)
},
// ...
)
किसी आइटम पर क्लिक करने पर अतिरिक्त व्यवहार जोड़ने के लिए, यह Lambda फ़ंक्शन पहले बनाए गए नेविगेटर का इस्तेमाल करता है. यह इस फ़ंक्शन में पास किए गए मूल Lambda फ़ंक्शन को कॉल करेगा. इसके बाद, 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
बनाता है जो नेविगेटर के वापस नेविगेट करने पर चालू होता है. साथ ही, यह Lambda फ़ंक्शन में, navigateBack()
को कॉल करता है. साथ ही, पैनल के बीच ट्रांज़िशन को ज़्यादा आसान बनाने के लिए, हर पैनल को AnimatedPane()
कंपोज़ेबल में रैप किया जाता है.
अलग-अलग तरह के डिवाइसों के लिए, साइज़ बदलने वाले एम्युलेटर पर ऐप्लिकेशन को फिर से चलाएं. साथ ही, ध्यान दें कि जब भी स्क्रीन कॉन्फ़िगरेशन में बदलाव होता है या किसी फ़ोल्ड किए जा रहे डिवाइस को अनफ़ोल्ड किया जाता है, तब डिवाइस की स्थिति के हिसाब से नेविगेशन और स्क्रीन का कॉन्टेंट डाइनैमिक तौर पर बदलता रहता है. साथ ही, सूची वाले पैनल में ईमेल पर टैप करके देखें कि लेआउट अलग-अलग स्क्रीन पर कैसा काम करता है. साथ ही, दोनों पैनल साथ-साथ दिखाते हैं या उनके बीच आसानी से ऐनिमेट होते हैं.
बधाई हो, आपने अपने ऐप्लिकेशन को सभी तरह के डिवाइस की स्थितियों और साइज़ के मुताबिक बना लिया है. फ़ोल्ड किए जा सकने वाले डिवाइस, टैबलेट या अन्य मोबाइल डिवाइसों पर इस ऐप्लिकेशन को चलाकर देखें.
6. बधाई हो
बधाई हो! आपने इस कोडलैब को पूरा कर लिया है और Jetpack Compose की मदद से ऐप्लिकेशन के हिसाब से ऐप्लिकेशन बनाने का तरीका सीख लिया है.
आपने डिवाइस के साइज़ और फ़ोल्ड की स्थिति देखने के साथ-साथ अपने ऐप्लिकेशन के यूज़र इंटरफ़ेस (यूआई), नेविगेशन, और अन्य फ़ंक्शन को अपडेट करने का तरीका सीखा है. साथ ही, आपको यह भी पता चला है कि ज़रूरत के हिसाब से ढलने की सुविधा से, लोगों तक कैसे पहुंचा जा सकता है और उपयोगकर्ता अनुभव को कैसे बेहतर बनाया जा सकता है.
आगे क्या करना है?
लिखें पाथ पर अन्य कोडलैब देखें.
सैंपल ऐप्लिकेशन
- कंपोज़ सैंपल, कई ऐप्लिकेशन का कलेक्शन होते हैं. इनमें कोडलैब में बताए गए सबसे सही तरीके शामिल होते हैं.