मॉडिफ़ायर की मदद से, किसी कंपोज़ेबल को बेहतर बनाया जा सकता है या उसमें बदलाव किया जा सकता है. मॉडिफ़ायर की मदद से, इस तरह के काम किए जा सकते हैं:
- कंपोज़ेबल के साइज़, लेआउट, व्यवहार, और दिखने के तरीके में बदलाव करना
- जानकारी जोड़ना, जैसे कि सुलभता लेबल
- उपयोगकर्ता के इनपुट को प्रोसेस करना
- बेहतर इंटरैक्शन जोड़ें. जैसे, किसी एलिमेंट को क्लिक किया जा सकने वाला, स्क्रोल किया जा सकने वाला, खींचा जा सकने वाला या ज़ूम किया जा सकने वाला बनाएं
मॉडिफ़ायर, स्टैंडर्ड Kotlin ऑब्जेक्ट होते हैं. Modifier
क्लास के किसी फ़ंक्शन को कॉल करके, एक मॉडिफ़ायर बनाएं:
@Composable private fun Greeting(name: String) { Column(modifier = Modifier.padding(24.dp)) { Text(text = "Hello,") Text(text = name) } }
इन फ़ंक्शन को एक साथ इस्तेमाल करके, कंपोज़ किया जा सकता है:
@Composable private fun Greeting(name: String) { Column( modifier = Modifier .padding(24.dp) .fillMaxWidth() ) { Text(text = "Hello,") Text(text = name) } }
ऊपर दिए गए कोड में, एक साथ इस्तेमाल किए गए अलग-अलग मॉडिफ़ायर फ़ंक्शन देखें.
padding
किसी एलिमेंट के चारों ओर स्पेस जोड़ता है.fillMaxWidth
की मदद से, कंपोज़ेबल को उसके पैरंट से मिली ज़्यादा से ज़्यादा चौड़ाई मिलती है.
सभी कंपोज़ेबल के लिए, modifier
पैरामीटर स्वीकार करना सबसे सही तरीका है. साथ ही, उस मॉडिफ़ायर को यूज़र इंटरफ़ेस (यूआई) दिखाने वाले पहले चाइल्ड को पास करना चाहिए.
ऐसा करने से, आपके कोड का दोबारा इस्तेमाल किया जा सकता है. साथ ही, इसके व्यवहार का अनुमान लगाना और इसे समझना आसान हो जाता है. ज़्यादा जानकारी के लिए, Compose API के दिशा-निर्देश देखें. साथ ही, Elements accept and respect a
Modifier parameter देखें.
मॉडिफ़ायर का क्रम मायने रखता है
मॉडिफ़ायर फ़ंक्शन का क्रम अहम होता है. हर फ़ंक्शन, पिछले फ़ंक्शन से मिले नतीजे में बदलाव करता है. इसलिए, क्रम से फ़ंक्शन लागू करने पर ही सही नतीजा मिलता है.Modifier
इसका एक उदाहरण यहां दिया गया है:
@Composable fun ArtistCard(/*...*/) { val padding = 16.dp Column( Modifier .clickable(onClick = onClick) .padding(padding) .fillMaxWidth() ) { // rest of the implementation } }
ऊपर दिए गए कोड में, पूरी जगह पर क्लिक किया जा सकता है. इसमें आस-पास की पैडिंग भी शामिल है. ऐसा इसलिए है, क्योंकि clickable
मॉडिफ़ायर के बाद padding
मॉडिफ़ायर लागू किया गया है. अगर मॉडिफ़ायर का क्रम उलट दिया जाता है, तो padding
से जोड़े गए स्पेस पर उपयोगकर्ता के इनपुट का कोई असर नहीं पड़ता:
@Composable fun ArtistCard(/*...*/) { val padding = 16.dp Column( Modifier .padding(padding) .clickable(onClick = onClick) .fillMaxWidth() ) { // rest of the implementation } }
पहले से मौजूद मॉडिफ़ायर
Jetpack Compose, पहले से मौजूद मॉडिफ़ायर की सूची उपलब्ध कराता है. इससे आपको किसी कंपोज़ेबल को बेहतर बनाने या उसे बढ़ाने में मदद मिलती है. यहां कुछ सामान्य मॉडिफ़ायर दिए गए हैं जिनका इस्तेमाल करके, लेआउट में बदलाव किया जा सकता है.
padding
और size
डिफ़ॉल्ट रूप से, Compose में दिए गए लेआउट, अपने चाइल्ड कॉम्पोनेंट को रैप करते हैं. हालांकि,
size
मॉडिफ़ायर का इस्तेमाल करके साइज़ सेट किया जा सकता है:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image(/*...*/) Column { /*...*/ } } }
ध्यान दें कि अगर आपने तय किया गया साइज़, लेआउट के पैरंट से मिली शर्तों को पूरा नहीं करता है, तो हो सकता है कि उसे लागू न किया जाए. अगर आपको कंपोज़ेबल का साइज़ तय करना है, भले ही आने वाली बाधाएं कुछ भी हों, तो requiredSize
मॉडिफ़ायर का इस्तेमाल करें:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image( /*...*/ modifier = Modifier.requiredSize(150.dp) ) Column { /*...*/ } } }
इस उदाहरण में, पैरंट height
को 100.dp
पर सेट करने के बावजूद, Image
की ऊंचाई 150.dp
होगी. ऐसा इसलिए, क्योंकि requiredSize
मॉडिफ़ायर को प्राथमिकता दी जाती है.
अगर आपको चाइल्ड लेआउट को पैरंट लेआउट की पूरी ऊंचाई में दिखाना है, तो fillMaxHeight
मॉडिफ़ायर जोड़ें. Compose में fillMaxSize
और fillMaxWidth
भी उपलब्ध हैं:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.size(width = 400.dp, height = 100.dp) ) { Image( /*...*/ modifier = Modifier.fillMaxHeight() ) Column { /*...*/ } } }
किसी एलिमेंट के चारों ओर पैडिंग जोड़ने के लिए, padding
मॉडिफ़ायर सेट करें.
अगर आपको टेक्स्ट की बेसलाइन के ऊपर पैडिंग जोड़नी है, ताकि लेआउट के सबसे ऊपर वाले हिस्से से बेसलाइन तक की दूरी तय की जा सके, तो paddingFromBaseline
मॉडिफ़ायर का इस्तेमाल करें:
@Composable fun ArtistCard(artist: Artist) { Row(/*...*/) { Column { Text( text = artist.name, modifier = Modifier.paddingFromBaseline(top = 50.dp) ) Text(artist.lastSeenOnline) } } }
ऑफ़सेट
किसी लेआउट को उसकी ओरिजनल जगह के हिसाब से सेट करने के लिए, offset
मॉडिफ़ायर जोड़ें. इसके बाद, x और y ऐक्सिस में ऑफ़सेट सेट करें.
ऑफ़सेट पॉज़िटिव और नॉन-पॉज़िटिव, दोनों हो सकते हैं. padding
और offset
में यह अंतर है कि कंपोज़ेबल में offset
जोड़ने से, उसके मेज़रमेंट में कोई बदलाव नहीं होता:
@Composable fun ArtistCard(artist: Artist) { Row(/*...*/) { Column { Text(artist.name) Text( text = artist.lastSeenOnline, modifier = Modifier.offset(x = 4.dp) ) } } }
offset
मॉडिफ़ायर को लेआउट की दिशा के हिसाब से हॉरिज़ॉन्टल तौर पर लागू किया जाता है.
बाएं से दाएं के हिसाब से, पॉज़िटिव offset
वैल्यू से एलिमेंट दाईं ओर खिसक जाता है. वहीं, दाएं से बाएं के हिसाब से, इससे एलिमेंट बाईं ओर खिसक जाता है.
अगर आपको लेआउट की दिशा को ध्यान में रखे बिना ऑफ़सेट सेट करना है, तो absoluteOffset
मॉडिफ़ायर देखें. इसमें, पॉज़िटिव ऑफ़सेट वैल्यू हमेशा एलिमेंट को दाईं ओर ले जाती है.
offset
मॉडिफ़ायर दो ओवरलोड देता है - offset
, जो ऑफ़सेट को पैरामीटर के तौर पर लेता है और offset
, जो लैम्डा को इनपुट के तौर पर लेता है.
इनमें से हर एक का इस्तेमाल कब करना है और परफ़ॉर्मेंस को ऑप्टिमाइज़ कैसे करना है, इसके बारे में ज़्यादा जानकारी के लिए, कंपोज़ परफ़ॉर्मेंस - ज़्यादा से ज़्यादा समय तक रीड को स्थगित करें सेक्शन पढ़ें.
Compose में स्कोप की सुरक्षा
Compose में ऐसे मॉडिफ़ायर होते हैं जिनका इस्तेमाल सिर्फ़ कुछ कंपोज़ेबल पर लागू होने पर किया जा सकता है. Compose, कस्टम स्कोप की मदद से इसे लागू करता है.
उदाहरण के लिए, अगर आपको किसी बच्चे को माता-पिता Box
जितना बड़ा बनाना है, लेकिन Box
के साइज़ पर कोई असर नहीं डालना है, तो matchParentSize
मॉडिफ़ायर का इस्तेमाल करें. matchParentSize
सिर्फ़ BoxScope
में उपलब्ध है.
इसलिए, इसका इस्तेमाल सिर्फ़ Box
के किसी बच्चे के लिए किया जा सकता है.
स्कोप की सुरक्षा से, आपको ऐसे मॉडिफ़ायर जोड़ने से रोका जाता है जो अन्य कंपोज़ेबल और स्कोप में काम नहीं करेंगे. इससे, आपको बार-बार कोशिश करने में लगने वाले समय की बचत होती है.
स्कोप किए गए मॉडिफ़ायर, माता-पिता को कुछ ऐसी जानकारी के बारे में सूचना देते हैं जिसके बारे में उन्हें अपने बच्चे के बारे में पता होना चाहिए. इन्हें आम तौर पर पैरंट डेटा मॉडिफ़ायर भी कहा जाता है. इनके इंटरनल, सामान्य तौर पर इस्तेमाल होने वाले मॉडिफ़ायर से अलग होते हैं. हालांकि, इस्तेमाल करने के लिहाज़ से, इन अंतरों से कोई फ़र्क़ नहीं पड़ता.
matchParentSize
, Box
में है
ऊपर बताया गया है कि अगर आपको किसी चाइल्ड लेआउट का साइज़, पैरंट लेआउट के साइज़ के बराबर रखना है, तो Box
के साइज़ पर असर डाले बिना Box
मॉडिफ़ायर का इस्तेमाल करें.matchParentSize
ध्यान दें कि matchParentSize
सिर्फ़ Box
स्कोप में उपलब्ध है. इसका मतलब है कि यह सिर्फ़ Box
कंपोज़ेबल के सीधे चाइल्ड पर लागू होता है.
यहां दिए गए उदाहरण में, चाइल्ड Spacer
का साइज़, पैरंट Box
से लिया गया है. वहीं, पैरंट Box
का साइज़, सबसे बड़े चाइल्ड ArtistCard
से लिया गया है.
@Composable fun MatchParentSizeComposable() { Box { Spacer( Modifier .matchParentSize() .background(Color.LightGray) ) ArtistCard() } }
अगर matchParentSize
की जगह fillMaxSize
का इस्तेमाल किया जाता, तो Spacer
, पैरंट के लिए उपलब्ध पूरी जगह ले लेता. इससे पैरंट का साइज़ बढ़ जाता और वह पूरी जगह भर देता.
Row
और Column
में weight
आपने पैडिंग और साइज़ के बारे में पिछले सेक्शन में देखा है कि डिफ़ॉल्ट रूप से, कंपोज़ेबल का साइज़ उस कॉन्टेंट से तय होता है जिसे वह रैप कर रहा है. weight
मॉडिफ़ायर का इस्तेमाल करके, किसी कंपोज़ेबल के साइज़ को उसके पैरंट के हिसाब से सेट किया जा सकता है. यह मॉडिफ़ायर सिर्फ़ RowScope
और ColumnScope
में उपलब्ध है.
आइए, एक ऐसा Row
लेते हैं जिसमें दो Box
कंपोज़ेबल शामिल हैं.
पहले बॉक्स को दूसरे बॉक्स के weight
से दोगुना दिया गया है. इसलिए, इसे चौड़ाई भी दोगुनी दी गई है. Row
की चौड़ाई 210.dp
है. इसलिए, पहले Box
की चौड़ाई 140.dp
है और दूसरे की चौड़ाई 70.dp
है:
@Composable fun ArtistCard(/*...*/) { Row( modifier = Modifier.fillMaxWidth() ) { Image( /*...*/ modifier = Modifier.weight(2f) ) Column( modifier = Modifier.weight(1f) ) { /*...*/ } } }
मॉडिफ़ायर को एक्सट्रैक्ट करना और उनका फिर से इस्तेमाल करना
एक कंपोज़ेबल को बेहतर बनाने या उसमें बदलाव करने के लिए, कई मॉडिफ़ायर को एक साथ जोड़ा जा सकता है. इस चेन को Modifier
इंटरफ़ेस के ज़रिए बनाया जाता है. यह एक क्रम वाली ऐसी सूची होती है जिसमें बदलाव नहीं किया जा सकता. इसमें एक ही Modifier.Elements
होता है.
हर Modifier.Element
, किसी एक व्यवहार को दिखाता है. जैसे, लेआउट, ड्रॉइंग, और ग्राफ़िक से जुड़े व्यवहार, सभी जेस्चर से जुड़े व्यवहार, फ़ोकस, और सिमैंटिक्स से जुड़े व्यवहार. साथ ही, डिवाइस इनपुट इवेंट. इनका क्रम मायने रखता है: सबसे पहले जोड़े गए मॉडिफ़ायर एलिमेंट, सबसे पहले लागू होंगे.
कभी-कभी, एक ही मॉडिफ़ायर चेन के इंस्टेंस को कई कंपोज़ेबल में फिर से इस्तेमाल करना फ़ायदेमंद हो सकता है. इसके लिए, उन्हें वैरिएबल में एक्सट्रैक्ट करें और उन्हें बड़े स्कोप में ले जाएं. इससे कोड को आसानी से समझा जा सकता है. साथ ही, कुछ वजहों से आपके ऐप्लिकेशन की परफ़ॉर्मेंस को बेहतर बनाने में मदद मिल सकती है:
- मॉडिफ़ायर को फिर से असाइन करने की प्रोसेस तब नहीं दोहराई जाएगी, जब उनका इस्तेमाल करने वाले कंपोज़ेबल के लिए फिर से कंपोज़िशन की जाएगी
- मॉडिफ़ायर चेन बहुत लंबी और जटिल हो सकती हैं. इसलिए, चेन के एक ही इंस्टेंस का दोबारा इस्तेमाल करने से, Compose रनटाइम को तुलना करते समय कम वर्कलोड की ज़रूरत पड़ सकती है
- इस एक्सट्रैक्शन से, कोडबेस में कोड को साफ़-सुथरा, एक जैसा, और रखरखाव में आसान बनाने में मदद मिलती है
मॉडिफ़ायर का फिर से इस्तेमाल करने के सबसे सही तरीके
अपनी Modifier
चेन बनाएं और उन्हें कई कंपोज़ेबल कॉम्पोनेंट पर फिर से इस्तेमाल करने के लिए एक्सट्रैक्ट करें. सिर्फ़ एक मॉडिफ़ायर को सेव करना ठीक है, क्योंकि ये डेटा जैसे ऑब्जेक्ट होते हैं:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp)
बार-बार बदलने वाली स्थिति को मॉनिटर करते समय, मॉडिफ़ायर को एक्सट्रैक्ट करना और उनका फिर से इस्तेमाल करना
कंपोज़ेबल के अंदर बार-बार बदलने वाली स्थितियों को देखने पर, जैसे कि ऐनिमेशन की स्थितियां या scrollState
, कई बार रेंडरिंग हो सकती है. इस मामले में, आपके मॉडिफ़ायर को हर रीकंपोज़िशन पर और संभावित तौर पर हर फ़्रेम के लिए असाइन किया जाएगा:
@Composable fun LoadingWheelAnimation() { val animatedState = animateFloatAsState(/*...*/) LoadingWheel( // Creation and allocation of this modifier will happen on every frame of the animation! modifier = Modifier .padding(12.dp) .background(Color.Gray), animatedState = animatedState ) }
इसके बजाय, मॉडिफ़ायर का एक ही इंस्टेंस बनाया जा सकता है, उसे निकाला जा सकता है, और फिर से इस्तेमाल किया जा सकता है. इसके बाद, उसे इस तरह कंपोज़ेबल को पास किया जा सकता है:
// Now, the allocation of the modifier happens here: val reusableModifier = Modifier .padding(12.dp) .background(Color.Gray) @Composable fun LoadingWheelAnimation() { val animatedState = animateFloatAsState(/*...*/) LoadingWheel( // No allocation, as we're just reusing the same instance modifier = reusableModifier, animatedState = animatedState ) }
बिना स्कोप वाले मॉडिफ़ायर को एक्सट्रैक्ट करना और उनका फिर से इस्तेमाल करना
मॉडिफ़ायर को किसी खास कंपोज़ेबल के लिए स्कोप किया जा सकता है या स्कोप नहीं किया जा सकता. बिना स्कोप वाले मॉडिफ़ायर के मामले में, उन्हें किसी भी कंपोज़ेबल के बाहर सामान्य वैरिएबल के तौर पर आसानी से निकाला जा सकता है:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) @Composable fun AuthorField() { HeaderText( // ... modifier = reusableModifier ) SubtitleText( // ... modifier = reusableModifier ) }
लेज़ी लेआउट के साथ इसका इस्तेमाल करने पर, खास तौर पर फ़ायदा मिल सकता है. ज़्यादातर मामलों में, आपको अपने सभी प्रॉडक्ट के लिए एक जैसे मॉडिफ़ायर चाहिए होते हैं. ऐसा इसलिए, ताकि आपको ज़्यादा से ज़्यादा फ़ायदा मिल सके:
val reusableItemModifier = Modifier .padding(bottom = 12.dp) .size(216.dp) .clip(CircleShape) @Composable private fun AuthorList(authors: List<Author>) { LazyColumn { items(authors) { AsyncImage( // ... modifier = reusableItemModifier, ) } } }
स्कोप किए गए मॉडिफ़ायर को निकालना और उनका फिर से इस्तेमाल करना
कुछ कंपोज़ेबल के लिए स्कोप किए गए मॉडिफ़ायर का इस्तेमाल करते समय, उन्हें सबसे ऊंचे लेवल पर एक्सट्रैक्ट किया जा सकता है. साथ ही, ज़रूरत के हिसाब से उनका फिर से इस्तेमाल किया जा सकता है:
Column(/*...*/) { val reusableItemModifier = Modifier .padding(bottom = 12.dp) // Align Modifier.Element requires a ColumnScope .align(Alignment.CenterHorizontally) .weight(1f) Text1( modifier = reusableItemModifier, // ... ) Text2( modifier = reusableItemModifier // ... ) // ... }
आपको सिर्फ़ निकाले गए और स्कोप किए गए मॉडिफ़ायर को, एक ही स्कोप वाले डायरेक्ट चाइल्ड को पास करना चाहिए. इस बारे में ज़्यादा जानने के लिए कि यह क्यों ज़रूरी है, Compose में स्कोप की सुरक्षा सेक्शन देखें:
Column(modifier = Modifier.fillMaxWidth()) { // Weight modifier is scoped to the Column composable val reusableItemModifier = Modifier.weight(1f) // Weight will be properly assigned here since this Text is a direct child of Column Text1( modifier = reusableItemModifier // ... ) Box { Text2( // Weight won't do anything here since the Text composable is not a direct child of Column modifier = reusableItemModifier // ... ) } }
निकाले गए मॉडिफ़ायर को एक साथ जोड़ना
.then()
फ़ंक्शन को कॉल करके, निकाली गई मॉडिफ़ायर चेन को आगे बढ़ाया जा सकता है या उनमें जोड़ा जा सकता है:
val reusableModifier = Modifier .fillMaxWidth() .background(Color.Red) .padding(12.dp) // Append to your reusableModifier reusableModifier.clickable { /*...*/ } // Append your reusableModifier otherModifier.then(reusableModifier)
बस यह ध्यान रखें कि मॉडिफ़ायर का क्रम मायने रखता है!
ज़्यादा जानें
हम मॉडिफ़ायर की पूरी सूची देते हैं. इसमें उनके पैरामीटर और स्कोप शामिल होते हैं.
मॉडिफ़ायर इस्तेमाल करने के बारे में ज़्यादा जानने के लिए, Compose में बुनियादी लेआउट कोडलैब पर जाएं. इसके अलावा, Now in Android रिपॉज़िटरी देखें.
कस्टम मॉडिफ़ायर और उन्हें बनाने के तरीके के बारे में ज़्यादा जानने के लिए, कस्टम लेआउट - लेआउट मॉडिफ़ायर का इस्तेमाल करना लेख पढ़ें.
आपके लिए सुझाव
- ध्यान दें: JavaScript बंद होने पर लिंक टेक्स्ट दिखता है
- ईमेल लिखने के लेआउट के बारे में बुनियादी बातें
- एडिटर की कार्रवाइयां {:#editor-actions}
- कस्टम लेआउट {:#custom-layouts }