Compose, अन्य यूज़र इंटरफ़ेस (यूआई) टूलकिट की तरह, किसी फ़्रेम को कई अलग-अलग फ़ेज़ में रेंडर करता है. उदाहरण के लिए, Android View सिस्टम के तीन मुख्य फ़ेज़ होते हैं: मेज़रमेंट, लेआउट, और ड्रॉइंग. Compose भी इसी तरह काम करता है. हालांकि, इसमें एक और अहम फ़ेज़ होता है, जिसे कंपोज़िशन कहा जाता है. यह फ़ेज़, Compose के शुरू होने पर काम करता है.
Compose के दस्तावेज़ में, कंपोज़िशन के बारे में जानकारी, Compose में सोचने का तरीका और स्टेट और Jetpack Compose लेखों में दी गई है.
किसी फ़्रेम के तीन फ़ेज़
Compose के तीन मुख्य फ़ेज़ होते हैं:
- कंपोज़िशन: यूज़र इंटरफ़ेस (यूआई) का कौनसा हिस्सा दिखाना है. Compose, कंपोज़ेबल फ़ंक्शन चलाता है और आपके यूज़र इंटरफ़ेस (यूआई) की जानकारी बनाता है.
- लेआउट: यूज़र इंटरफ़ेस (यूआई) को कहां रखना है. इस फ़ेज़ में दो चरण होते हैं: मेज़रमेंट और प्लेसमेंट. लेआउट एलिमेंट, लेआउट ट्री में मौजूद हर नोड के लिए, 2D कोऑर्डिनेट में खुद को और चाइल्ड एलिमेंट को मेज़र और प्लेस करते हैं.
- ड्रॉइंग: यह कैसे रेंडर होता है. यूज़र इंटरफ़ेस (यूआई) एलिमेंट, आम तौर पर डिवाइस की स्क्रीन पर कैनवस में ड्रॉ होते हैं.
आम तौर पर, इन फ़ेज़ का क्रम एक जैसा होता है. इससे डेटा, कंपोज़िशन से लेआउट, लेआउट से ड्रॉइंग, और ड्रॉइंग से फ़्रेम बनाने के लिए एक ही
दिशा में फ़्लो होता है. इसे यूनिडायरेक्शनल डेटा फ़्लो भी कहा जाता है. BoxWithConstraints, LazyColumn, और LazyRow इसके अहम अपवाद हैं. इनमें चाइल्ड एलिमेंट का कंपोज़िशन, पैरंट के लेआउट फ़ेज़ पर निर्भर करता है.
सैद्धांतिक तौर पर, इनमें से हर फ़ेज़ हर फ़्रेम के लिए होता है. हालांकि, परफ़ॉर्मेंस को ऑप्टिमाइज़ करने के लिए, Compose इन सभी फ़ेज़ में एक ही इनपुट से एक जैसे नतीजे देने वाले काम को दोहराने से बचता है. अगर Compose, पहले के किसी नतीजे का फिर से इस्तेमाल कर सकता है, तो वह कंपोज़ेबल फ़ंक्शन को रन नहीं करता. साथ ही, अगर Compose यूज़र इंटरफ़ेस (यूआई) को पूरे ट्री को फिर से लेआउट या रीड्रॉ करने की ज़रूरत नहीं होती, तो वह ऐसा नहीं करता. Compose, यूज़र इंटरफ़ेस (यूआई) को अपडेट करने के लिए सिर्फ़ उतना काम करता है जितना ज़रूरी होता है. यह ऑप्टिमाइज़ेशन इसलिए किया जा सकता है, क्योंकि Compose अलग-अलग फ़ेज़ में स्टेट रीड को ट्रैक करता है.
फ़ेज़ के बारे में जानकारी
इस सेक्शन में, कंपोज़ेबल के लिए Compose के तीनों फ़ेज़ के काम करने के तरीके के बारे में ज़्यादा जानकारी दी गई है.
कंपोज़िशन
कंपोज़िशन फ़ेज़ में, Compose रनटाइम, कंपोज़ेबल फ़ंक्शन को एक्ज़ीक्यूट करता है और एक ट्री स्ट्रक्चर आउटपुट करता है. यह स्ट्रक्चर, आपके यूज़र इंटरफ़ेस (यूआई) को दिखाता है. इस यूज़र इंटरफ़ेस (यूआई) ट्री में लेआउट नोड होते हैं. इनमें अगले फ़ेज़ के लिए ज़रूरी सभी जानकारी होती है, जैसा कि यहां दिए गए वीडियो में दिखाया गया है:
दूसरी इमेज. यह ट्री, आपके यूज़र इंटरफ़ेस (यूआई) को दिखाता है. इसे कंपोज़िशन फ़ेज़ में बनाया जाता है.
कोड और यूज़र इंटरफ़ेस (यूआई) ट्री का एक सबसेक्शन यहां दिया गया है:
इन उदाहरणों में, कोड में मौजूद हर कंपोज़ेबल फ़ंक्शन, यूज़र इंटरफ़ेस (यूआई) ट्री में मौजूद एक लेआउट नोड से मैप होता है. ज़्यादा जटिल उदाहरणों में, कंपोज़ेबल में लॉजिक और कंट्रोल फ़्लो शामिल हो सकता है. साथ ही, अलग-अलग स्टेट के लिए अलग-अलग ट्री जनरेट किए जा सकते हैं.
लेआउट
लेआउट फ़ेज़ में, Compose, कंपोज़िशन फ़ेज़ में जनरेट किए गए यूज़र इंटरफ़ेस (यूआई) ट्री को इनपुट के तौर पर इस्तेमाल करता है. लेआउट नोड के कलेक्शन में, 2D स्पेस में हर नोड के साइज़ और जगह के बारे में फ़ैसला लेने के लिए ज़रूरी सभी जानकारी होती है.
चौथी इमेज. लेआउट फ़ेज़ के दौरान, यूज़र इंटरफ़ेस (यूआई) ट्री में मौजूद हर लेआउट नोड का मेज़रमेंट और प्लेसमेंट दिखाया गया है.
लेआउट फ़ेज़ के दौरान, ट्री को तीन चरणों वाले इस एल्गोरिदम का इस्तेमाल करके ट्रैवर्स किया जाता है:
- चाइल्ड एलिमेंट को मेज़र करना: अगर किसी नोड में चाइल्ड एलिमेंट मौजूद हैं, तो वह उन्हें मेज़र करता है.
- अपना साइज़ तय करना: इन मेज़रमेंट के आधार पर, कोई नोड अपना साइज़ तय करता है.
- चाइल्ड एलिमेंट को प्लेस करना: हर चाइल्ड नोड को, नोड की अपनी पोज़िशन के हिसाब से प्लेस किया जाता है.
इस फ़ेज़ के आखिर में, हर लेआउट नोड में ये चीज़ें होती हैं:
- असाइन की गई चौड़ाई और ऊंचाई
- x, y कोऑर्डिनेट जहां इसे ड्रॉ किया जाना चाहिए
पिछले सेक्शन में मौजूद यूज़र इंटरफ़ेस (यूआई) ट्री को याद करें:
इस ट्री के लिए, एल्गोरिदम इस तरह काम करता है:
Row, अपने चाइल्ड एलिमेंटImageऔरColumnको मेज़र करता है.Imageको मेज़र किया जाता है. इसमें कोई चाइल्ड एलिमेंट नहीं होता. इसलिए, यह अपना साइज़ तय करता है औरRowको साइज़ की जानकारी देता है.- इसके बाद,
Columnको मेज़र किया जाता है. यह सबसे पहले अपने चाइल्ड एलिमेंट (दोTextकंपोज़ेबल) को मेज़र करता है. - पहले
Textको मेज़र किया जाता है. इसमें कोई चाइल्ड एलिमेंट नहीं होता. इसलिए, यह अपना साइज़ तय करता है औरColumnको साइज़ की जानकारी देता है.- दूसरे
Textको मेज़र किया जाता है. इसमें कोई चाइल्ड एलिमेंट नहीं होता. इसलिए, यह अपना साइज़ तय करता है औरColumnको साइज़ की जानकारी देता है.
- दूसरे
Column, चाइल्ड एलिमेंट के मेज़रमेंट का इस्तेमाल करके अपना साइज़ तय करता है. यह चाइल्ड एलिमेंट की ज़्यादा से ज़्यादा चौड़ाई और उनकी ऊंचाई के योग का इस्तेमाल करता है.Column, अपने चाइल्ड एलिमेंट को अपनी पोज़िशन के हिसाब से प्लेस करता है. इसके लिए, वह उन्हें वर्टिकल तरीके से एक-दूसरे के नीचे रखता है.Row, चाइल्ड एलिमेंट के मेज़रमेंट का इस्तेमाल करके अपना साइज़ तय करता है. यह चाइल्ड एलिमेंट की ज़्यादा से ज़्यादा ऊंचाई और उनकी चौड़ाई के योग का इस्तेमाल करता है. इसके बाद, यह अपने चाइल्ड एलिमेंट को प्लेस करता है.
ध्यान दें कि हर नोड को सिर्फ़ एक बार विज़िट किया गया है. Compose रनटाइम को सभी नोड को मेज़र और प्लेस करने के लिए, यूज़र इंटरफ़ेस (यूआई) ट्री को सिर्फ़ एक बार ट्रैवर्स करना पड़ता है. इससे परफ़ॉर्मेंस बेहतर होती है. जब ट्री में नोड की संख्या बढ़ती है, तो उसे ट्रैवर्स करने में लगने वाला समय, लीनियर तरीके से बढ़ता है. इसके उलट, अगर हर नोड को कई बार विज़िट किया जाता है, तो ट्रैवर्सल का समय, एक्स्पोनेंशियल तरीके से बढ़ता है.
ड्रॉइंग
ड्रॉइंग फ़ेज़ में, ट्री को ऊपर से नीचे की ओर फिर से ट्रैवर्स किया जाता है. इसके बाद, हर नोड बारी-बारी से स्क्रीन पर खुद को ड्रॉ करता है.
पांचवीं इमेज. ड्रॉइंग फ़ेज़ में, स्क्रीन पर पिक्सल ड्रॉ किए जाते हैं.
पिछले उदाहरण का इस्तेमाल करके, ट्री के कॉन्टेंट को इस तरह ड्रॉ किया जाता है:
Row, अपना कोई भी कॉन्टेंट ड्रॉ करता है. जैसे, बैकग्राउंड का रंग.Image, खुद को ड्रॉ करता है.Column, खुद को ड्रॉ करता है.- पहला और दूसरा
Text, बारी-बारी से खुद को ड्रॉ करते हैं.
छठी इमेज. यह यूज़र इंटरफ़ेस (यूआई) ट्री और उसका ड्रॉ किया गया वर्शन दिखाता है.
स्टेट रीड
पहले बताए गए किसी फ़ेज़
के दौरान, snapshot state के value को पढ़ने पर, Compose अपने-आप ट्रैक करता है कि value को पढ़ते समय वह क्या कर रहा था. इस ट्रैकिंग की मदद से, Compose, स्टेट की value बदलने पर, रीडर को फिर से एक्ज़ीक्यूट कर सकता है. यह Compose में स्टेट ऑब्ज़र्वेबिलिटी का आधार है.
आम तौर पर, mutableStateOf() का इस्तेमाल करके स्टेट बनाई जाती है. इसके बाद, इसे दो तरीकों में से किसी एक तरीके से ऐक्सेस किया जाता है: सीधे value प्रॉपर्टी को ऐक्सेस करके या Kotlin प्रॉपर्टी डेलिगेट का इस्तेमाल करके. इनके बारे में ज़्यादा जानने के लिए, कंपोज़ेबल में स्टेट
लेख पढ़ें. इस गाइड के लिए, "स्टेट रीड" का मतलब, ऐक्सेस के इन दोनों तरीकों में से कोई एक है.
// State read without property delegate. val paddingState: MutableState<Dp> = remember { mutableStateOf(8.dp) } Text( text = "Hello", modifier = Modifier.padding(paddingState.value) )
// State read with property delegate. var padding: Dp by remember { mutableStateOf(8.dp) } Text( text = "Hello", modifier = Modifier.padding(padding) )
प्रॉपर्टी डेलिगेट के बैकएंड में, स्टेट की value को ऐक्सेस और अपडेट करने के लिए, "getter" और "setter"
फ़ंक्शन का इस्तेमाल किया जाता है. ये getter और setter फ़ंक्शन सिर्फ़ तब लागू होते हैं, जब प्रॉपर्टी को वैल्यू के तौर पर रेफ़रंस किया जाता है. ये तब लागू नहीं होते, जब प्रॉपर्टी बनाई जाती है. इसलिए, पहले बताए गए दोनों तरीके एक जैसे हैं.
कोड का हर वह ब्लॉक जिसे रीड स्टेट में बदलाव होने पर फिर से एक्ज़ीक्यूट किया जा सकता है, रीस्टार्ट स्कोप होता है. Compose, अलग-अलग फ़ेज़ में स्टेट की value में होने वाले बदलावों और रीस्टार्ट स्कोप को ट्रैक करता है.
फ़ेज़ के हिसाब से स्टेट रीड
जैसा कि पहले बताया गया है, Compose में तीन मुख्य फ़ेज़ होते हैं. Compose, इनमें से हर फ़ेज़ में पढ़ी गई स्टेट को ट्रैक करता है. इससे Compose, आपके यूज़र इंटरफ़ेस (यूआई) के हर उस एलिमेंट के लिए सिर्फ़ उन फ़ेज़ को सूचना दे सकता है जिन्हें काम करने की ज़रूरत है.
यहां दिए गए सेक्शन में, हर फ़ेज़ के बारे में बताया गया है. साथ ही, यह भी बताया गया है कि किसी फ़ेज़ में स्टेट की वैल्यू को पढ़ने पर क्या होता है.
पहला फ़ेज़: कंपोज़िशन
@Composable फ़ंक्शन या lambda ब्लॉक में स्टेट रीड, कंपोज़िशन और संभावित तौर पर अगले फ़ेज़ पर असर डालते हैं. जब स्टेट की value बदलती है, तो रीकंपोज़र, उन सभी कंपोज़ेबल फ़ंक्शन को फिर से रन करने का शेड्यूल बनाता है जिन्होंने उस स्टेट की value को पढ़ा है. ध्यान दें कि अगर इनपुट में कोई बदलाव नहीं हुआ है, तो रनटाइम, कुछ या सभी कंपोज़ेबल फ़ंक्शन को स्किप कर सकता है. ज़्यादा जानकारी के लिए, अगर इनपुट में कोई बदलाव नहीं हुआ है
, तो स्किप करना लेख पढ़ें.
कंपोज़िशन के नतीजे के आधार पर, Compose यूज़र इंटरफ़ेस (यूआई), लेआउट और ड्रॉइंग फ़ेज़ को रन करता है. अगर कॉन्टेंट में कोई बदलाव नहीं हुआ है और साइज़ और लेआउट में कोई बदलाव नहीं होगा, तो वह इन फ़ेज़ को स्किप कर सकता है.
var padding by remember { mutableStateOf(8.dp) } Text( text = "Hello", // The `padding` state is read in the composition phase // when the modifier is constructed. // Changes in `padding` will invoke recomposition. modifier = Modifier.padding(padding) )
दूसरा फ़ेज़: लेआउट
लेआउट फ़ेज़ में दो चरण होते हैं: मेज़रमेंट और प्लेसमेंट. मेज़रमेंट चरण में, Layout कंपोज़ेबल को पास किया गया मेज़र lambda, MeasureScope.measure इंटरफ़ेस का LayoutModifier तरीका वगैरह रन होता है.
प्लेसमेंट चरण में, layout फ़ंक्शन का प्लेसमेंट ब्लॉक, Modifier.offset { … } का lambda ब्लॉक, और इसी तरह के फ़ंक्शन रन होते हैं.
इनमें से हर चरण के दौरान स्टेट रीड, लेआउट और संभावित तौर पर ड्रॉइंग फ़ेज़ पर असर डालते हैं. जब स्टेट की value बदलती है, तो Compose यूज़र इंटरफ़ेस (यूआई), लेआउट फ़ेज़ का शेड्यूल बनाता है. अगर साइज़ या पोज़िशन में बदलाव हुआ है, तो वह ड्रॉइंग फ़ेज़ को भी रन करता है.
var offsetX by remember { mutableStateOf(8.dp) } Text( text = "Hello", modifier = Modifier.offset { // The `offsetX` state is read in the placement step // of the layout phase when the offset is calculated. // Changes in `offsetX` restart the layout. IntOffset(offsetX.roundToPx(), 0) } )
तीसरा फ़ेज़: ड्रॉइंग
ड्रॉइंग कोड के दौरान स्टेट रीड, ड्रॉइंग फ़ेज़ पर असर डालते हैं. इसके सामान्य उदाहरणों में Canvas(), Modifier.drawBehind, और Modifier.drawWithContent शामिल हैं. जब स्टेट की value बदलती है, तो Compose यूज़र इंटरफ़ेस (यूआई) सिर्फ़ ड्रॉ फ़ेज़ को रन करता है.
var color by remember { mutableStateOf(Color.Red) } Canvas(modifier = modifier) { // The `color` state is read in the drawing phase // when the canvas is rendered. // Changes in `color` restart the drawing. drawRect(color) }
स्टेट रीड को ऑप्टिमाइज़ करना
Compose, स्थानीय तौर पर स्टेट रीड ट्रैकिंग करता है. इसलिए, हर स्टेट को सही फ़ेज़ में पढ़कर, काम की मात्रा को कम किया जा सकता है.
यह उदाहरण देखें. इस उदाहरण में, Image() में ऑफ़सेट मॉडिफ़ायर का इस्तेमाल किया गया है. इससे, इमेज की फ़ाइनल लेआउट पोज़िशन ऑफ़सेट हो जाती है. इससे, उपयोगकर्ता के स्क्रोल करने पर पैरलैक्स इफ़ेक्ट मिलता है.
Box { val listState = rememberLazyListState() Image( // ... // Non-optimal implementation! Modifier.offset( with(LocalDensity.current) { // State read of firstVisibleItemScrollOffset in composition (listState.firstVisibleItemScrollOffset / 2).toDp() } ) ) LazyColumn(state = listState) { // ... } }
यह कोड काम करता है, लेकिन इससे परफ़ॉर्मेंस बेहतर नहीं होती. जैसा कि लिखा गया है, कोड
पढ़ता है value की firstVisibleItemScrollOffset स्टेट और उसे पास करता है
को Modifier.offset(offset: Dp) फ़ंक्शन. उपयोगकर्ता के स्क्रोल करने पर, firstVisibleItemScrollOffset की value बदल जाएगी. जैसा कि आपने सीखा है, Compose, सभी स्टेट रीड को ट्रैक करता है, ताकि वह रीडिंग कोड को रीस्टार्ट (फिर से लागू) कर सके. इस उदाहरण में, यह Box का कॉन्टेंट है.
यह कंपोज़िशन फ़ेज़ में स्टेट को पढ़ने का एक उदाहरण है. यह ज़रूरी नहीं कि यह कोई बुरी बात हो. असल में, यह रीकंपोज़िशन का आधार है. इससे डेटा में बदलाव होने पर, नया यूज़र इंटरफ़ेस (यूआई) जनरेट होता है.
अहम जानकारी: यह उदाहरण बेहतर नहीं है, क्योंकि हर स्क्रोल इवेंट की वजह से, पूरे कंपोज़ेबल कॉन्टेंट का फिर से आकलन किया जाता है, उसे मेज़र किया जाता है, उसका लेआउट बनाया जाता है, और आखिर में उसे ड्रॉ किया जाता है. हर स्क्रोल पर, Compose फ़ेज़ ट्रिगर होता है. भले ही, दिखाए गए कॉन्टेंट में कोई बदलाव न हुआ हो, सिर्फ़ उसकी पोज़िशन बदली हो. स्टेट रीड को ऑप्टिमाइज़ करके, सिर्फ़ लेआउट फ़ेज़ को फिर से ट्रिगर किया जा सकता है.
lambda के साथ ऑफ़सेट
ऑफ़सेट मॉडिफ़ायर का एक और वर्शन उपलब्ध है:
Modifier.offset(offset: Density.() -> IntOffset).
इस वर्शन में lambda पैरामीटर लिया जाता है. इसमें, lambda ब्लॉक से ऑफ़सेट की वैल्यू मिलती है. इसका इस्तेमाल करने के लिए, कोड को अपडेट करें:
Box { val listState = rememberLazyListState() Image( // ... Modifier.offset { // State read of firstVisibleItemScrollOffset in Layout IntOffset(x = 0, y = listState.firstVisibleItemScrollOffset / 2) } ) LazyColumn(state = listState) { // ... } }
तो, यह ज़्यादा परफ़ॉर्म क्यों करता है? मॉडिफ़ायर को दिया गया lambda ब्लॉक, लेआउट फ़ेज़ के दौरान लागू होता है. खास तौर पर, लेआउट फ़ेज़ के प्लेसमेंट चरण के दौरान. इसका मतलब है कि कंपोज़िशन के दौरान, firstVisibleItemScrollOffset स्टेट को अब नहीं पढ़ा जाता. Compose, स्टेट को कब पढ़ा जाता है, इसे ट्रैक करता है. इसलिए, इस बदलाव का मतलब है कि अगर firstVisibleItemScrollOffset की value बदलती है, तो Compose को सिर्फ़ लेआउट और ड्रॉइंग फ़ेज़ को रीस्टार्ट करना होगा.
ज़ाहिर है, कंपोज़िशन फ़ेज़ में स्टेट को पढ़ना अक्सर बहुत ज़रूरी होता है. इसके बावजूद, ऐसे मामले होते हैं जिनमें स्टेट में होने वाले बदलावों को फ़िल्टर करके, रीकंपोज़िशन की संख्या को कम किया जा सकता है. इसके बारे में ज़्यादा जानने के लिए,
देखें derivedStateOf: एक या एक से ज़्यादा स्टेट ऑब्जेक्ट को दूसरी
स्टेट में बदलना.
रीकंपोज़िशन लूप (साइक्लिक फ़ेज़ डिपेंडेंसी)
इस गाइड में पहले बताया गया था कि Compose के फ़ेज़ हमेशा एक ही क्रम में लागू होते हैं. साथ ही, एक ही फ़्रेम में पीछे जाने का कोई तरीका नहीं है. हालांकि, इससे ऐप्लिकेशन को अलग-अलग फ़्रेम में कंपोज़िशन लूप में जाने से नहीं रोका जा सकता. यह उदाहरण देखें:
Box { var imageHeightPx by remember { mutableIntStateOf(0) } Image( painter = painterResource(R.drawable.rectangle), contentDescription = "I'm above the text", modifier = Modifier .fillMaxWidth() .onSizeChanged { size -> // Don't do this imageHeightPx = size.height } ) Text( text = "I'm below the image", modifier = Modifier.padding( top = with(LocalDensity.current) { imageHeightPx.toDp() } ) ) }
इस उदाहरण में, वर्टिकल कॉलम लागू किया गया है. इसमें सबसे ऊपर इमेज है और उसके नीचे टेक्स्ट है. इसमें इमेज का रिज़ॉल्व किया गया साइज़ पाने के लिए, Modifier.onSizeChanged() का इस्तेमाल किया गया है. इसके बाद, टेक्स्ट को नीचे की ओर शिफ़्ट करने के लिए, Modifier.padding() का इस्तेमाल किया गया है.
Px से Dp में अस्वाभाविक कन्वर्ज़न से ही पता चलता है कि कोड में कोई समस्या है.
इस उदाहरण में समस्या यह है कि कोड, एक ही फ़्रेम में "फ़ाइनल" लेआउट पर नहीं पहुंचता. कोड, कई फ़्रेम पर निर्भर करता है. इससे गैर-ज़रूरी काम होता है. साथ ही, उपयोगकर्ता के लिए स्क्रीन पर यूज़र इंटरफ़ेस (यूआई) जंप करता है.
पहले फ़्रेम का कंपोज़िशन
पहले फ़्रेम के कंपोज़िशन फ़ेज़ के दौरान, imageHeightPx की शुरुआती वैल्यू 0 होती है. इसलिए, कोड, टेक्स्ट को Modifier.padding(top = 0) देता है.
इसके बाद के लेआउट फ़ेज़ में, onSizeChanged मॉडिफ़ायर का कॉलबैक लागू होता है. इससे imageHeightPx को इमेज की असल ऊंचाई पर अपडेट किया जाता है. इसके बाद, Compose, अगले फ़्रेम के लिए रीकंपोज़िशन का शेड्यूल बनाता है. हालांकि, मौजूदा ड्रॉइंग फ़ेज़ के दौरान, टेक्स्ट 0 की पैडिंग के साथ रेंडर होता है, क्योंकि अपडेट की गई imageHeightPx वैल्यू अब तक नहीं दिखती.
दूसरे फ़्रेम का कंपोज़िशन
Compose, दूसरे फ़्रेम को शुरू करता है. यह imageHeightPx की वैल्यू में बदलाव होने पर ट्रिगर होता है. इस फ़्रेम के कंपोज़िशन फ़ेज़ में, स्टेट को Box कॉन्टेंट ब्लॉक में पढ़ा जाता है. टेक्स्ट को अब ऐसी पैडिंग दी जाती है जो इमेज की ऊंचाई से सटीक तौर पर मेल खाती है. लेआउट फ़ेज़ के दौरान, imageHeightPx को फिर से सेट किया जाता है. हालांकि, कोई और रीकंपोज़िशन शेड्यूल नहीं किया जाता, क्योंकि वैल्यू एक जैसी रहती है.
यह उदाहरण बनावटी लग सकता है. हालांकि, इस सामान्य पैटर्न से सावधान रहें:
Modifier.onSizeChanged(),onGloballyPositioned(), या अन्य लेआउट कार्रवाइयां- किसी स्टेट को अपडेट करना
- उस स्टेट का इस्तेमाल, लेआउट मॉडिफ़ायर (
padding(),height(), या इसी तरह के मॉडिफ़ायर) के लिए इनपुट के तौर पर करना - संभावित तौर पर दोहराना
ऊपर दिए गए सैंपल को ठीक करने के लिए, सही लेआउट प्रिमिटिव का इस्तेमाल करें. ऊपर दिए गए उदाहरण को Column() के साथ लागू किया जा सकता है. हालांकि, आपके पास ज़्यादा जटिल उदाहरण हो सकता है. इसके लिए, आपको कस्टम लेआउट लिखना होगा. ज़्यादा जानकारी के लिए, कस्टम लेआउट गाइड देखें.
यहां सामान्य सिद्धांत यह है कि एक से ज़्यादा यूज़र इंटरफ़ेस (यूआई) एलिमेंट के लिए, सोर्स ऑफ़ ट्रुथ एक ही होना चाहिए. इन एलिमेंट को एक-दूसरे के हिसाब से मेज़र और प्लेस किया जाना चाहिए. सही लेआउट प्रिमिटिव का इस्तेमाल करने या कस्टम लेआउट बनाने का मतलब है कि कम से कम शेयर किया गया पैरंट, सोर्स ऑफ़ ट्रुथ के तौर पर काम करता है. यह एक से ज़्यादा एलिमेंट के बीच के संबंध को कोऑर्डिनेट कर सकता है. डाइनैमिक स्टेट लागू करने से यह सिद्धांत टूट जाता है.
आपके लिए सुझाव
- ध्यान दें: JavaScript बंद होने पर, लिंक का टेक्स्ट दिखता है
- स्टेट और Jetpack Compose
- सूचियां और ग्रिड
- Jetpack Compose के लिए Kotlin