मॉडिफ़ायर की मदद से, किसी कॉम्पोज़ेबल को सजाया या बेहतर बनाया जा सकता है. मॉडिफ़ायर की मदद से ये काम किए जा सकते हैं:
- कंपोज़ेबल के साइज़, लेआउट, व्यवहार, और लुक में बदलाव करें
- सुलभता के लेबल जैसी जानकारी जोड़ें
- उपयोगकर्ता का इनपुट प्रोसेस करें
- बेहतर इंटरैक्शन जोड़ें. जैसे, किसी एलिमेंट को क्लिक किया जा सकने वाला, स्क्रोल किया जा सकने वाला, खींचा और छोड़ा जा सकने वाला या ज़ूम किया जा सकने वाला बनाना
मॉडिफ़ायर, स्टैंडर्ड 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 के दिशा-निर्देश देखें. एलिमेंट, बदलाव करने वाले पैरामीटर को स्वीकार करते हैं और उसका इस्तेमाल करते हैं.
मॉडिफ़ायर का क्रम मायने रखता है
मॉडिफ़ायर फ़ंक्शन का क्रम अहम होता है. क्योंकि हर फ़ंक्शन बनाता है
पिछले फ़ंक्शन से मिलने वाले 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
में है
जैसा कि ऊपर बताया गया है, अगर आपको चाइल्ड लेआउट का साइज़, पैरंट लेआउट के साइज़ के बराबर रखना है, तो matchParentSize
मॉडिफ़ायर का इस्तेमाल करें. इससे Box
के साइज़ पर कोई असर नहीं पड़ेगा.
ध्यान दें कि matchParentSize
सिर्फ़ Box
दायरे में उपलब्ध है. इसका मतलब है कि
यह सिर्फ़ Box
कंपोज़ेबल के डायरेक्ट चाइल्ड पर लागू होता है.
नीचे दिए गए उदाहरण में, चाइल्ड Spacer
अपना साइज़ अपने पैरंट Box
से लेता है,
और बड़े बच्चों,
इस मामले में ArtistCard
.
@Composable fun MatchParentSizeComposable() { Box { Spacer( Modifier .matchParentSize() .background(Color.LightGray) ) ArtistCard() } }
अगर matchParentSize
के बजाय fillMaxSize
का इस्तेमाल किया जाता, तो Spacer
को
माता-पिता के लिए उपलब्ध स्टोरेज की वजह से, माता-पिता को
सभी उपलब्ध जगह को बड़ा करके भरें.
Row
और Column
में weight
जैसा कि आपने पैडिंग और साइज़ वाले पिछले सेक्शन में देखा है, डिफ़ॉल्ट रूप से किसी कॉम्पोज़ेबल का साइज़, उस कॉन्टेंट से तय होता है जिसे रैप किया जा रहा है. कंपोज़ेबल साइज़ को इस हिसाब से सेट किया जा सकता है कि साइज़
सिर्फ़ RowScope
में उपलब्ध weight
मॉडिफ़ायर का इस्तेमाल करने वाले माता-पिता, और
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 // ... ) // ... }
आपको सिर्फ़ निकाले गए, स्कोप वाले मॉडिफ़ायर को, एक ही स्कोप वाले डायरेक्ट चाइल्ड को पास करना चाहिए. इसके हिसाब से, स्कोप की सुरक्षा यह ज़रूरी क्यों है, इस बारे में ज़्यादा जानने के लिए लिखें:
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 कोडलैब में बुनियादी लेआउट देखें या Android के रिपॉज़िटरी में अब उपलब्ध है लेख पढ़ें.
कस्टम मॉडिफ़ायर और उन्हें बनाने के तरीके के बारे में ज़्यादा जानने के लिए, कस्टम लेआउट - लेआउट मॉडिफ़ायर का इस्तेमाल करना के बारे में जानकारी.
आपके लिए सुझाव
- ध्यान दें: JavaScript बंद होने पर लिंक टेक्स्ट दिखता है
- लेआउट बनाने की बुनियादी बातें
- एडिटर ऐक्शन {:#editor-actions}
- पसंद के मुताबिक लेआउट {:#custom-layouts }