Compose में, सामान्य व्यवहारों के लिए कई मॉडिफ़ायर पहले से मौजूद होते हैं. हालांकि, आपके पास अपने हिसाब से कस्टम मॉडिफ़ायर बनाने का विकल्प भी होता है.
मॉडिफ़ायर के कई हिस्से होते हैं:
- मॉडिफ़ायर फ़ैक्ट्री
- यह
Modifier
पर मौजूद एक एक्सटेंशन फ़ंक्शन है. यह आपके मॉडिफ़ायर के लिए, मुहावरेदार एपीआई उपलब्ध कराता है. साथ ही, मॉडिफ़ायर को एक साथ इस्तेमाल करने की अनुमति देता है. मॉडिफ़ायर फ़ैक्ट्री, ऐसे मॉडिफ़ायर एलिमेंट बनाती है जिनका इस्तेमाल Compose, आपके यूज़र इंटरफ़ेस (यूआई) में बदलाव करने के लिए करता है.
- यह
- मॉडिफ़ायर एलिमेंट
- यहां अपने मॉडिफ़ायर का व्यवहार लागू किया जा सकता है.
ज़रूरत के हिसाब से, कस्टम मॉडिफ़ायर को लागू करने के कई तरीके हैं. आम तौर पर, कस्टम मॉडिफ़ायर लागू करने का सबसे आसान तरीका यह है कि कस्टम मॉडिफ़ायर फ़ैक्ट्री लागू की जाए. यह फ़ैक्ट्री, पहले से तय की गई अन्य मॉडिफ़ायर फ़ैक्ट्रियों को एक साथ जोड़ती है. अगर आपको ज़्यादा कस्टम व्यवहार की ज़रूरत है, तो Modifier.Node
एपीआई का इस्तेमाल करके, मॉडिफ़ायर एलिमेंट लागू करें. ये एपीआई लोअर लेवल के होते हैं, लेकिन ज़्यादा फ़्लेक्सिबिलिटी देते हैं.
मौजूदा मॉडिफ़ायर को एक साथ जोड़ना
अक्सर, मौजूदा मॉडिफ़ायर का इस्तेमाल करके कस्टम मॉडिफ़ायर बनाए जा सकते हैं. उदाहरण के लिए, Modifier.clip()
को graphicsLayer
मॉडिफ़ायर का इस्तेमाल करके लागू किया जाता है. इस रणनीति में, पहले से मौजूद मॉडिफ़ायर एलिमेंट का इस्तेमाल किया जाता है. साथ ही, आपको अपना कस्टम मॉडिफ़ायर फ़ैक्ट्री देना होता है.
अपने कस्टम मॉडिफ़ायर को लागू करने से पहले, देखें कि क्या उसी रणनीति का इस्तेमाल किया जा सकता है.
fun Modifier.clip(shape: Shape) = graphicsLayer(shape = shape, clip = true)
इसके अलावा, अगर आपको लगता है कि एक ही तरह के मॉडिफ़ायर का इस्तेमाल बार-बार किया जा रहा है, तो उन्हें अपने मॉडिफ़ायर में शामिल किया जा सकता है:
fun Modifier.myBackground(color: Color) = padding(16.dp) .clip(RoundedCornerShape(8.dp)) .background(color)
कंपोज़ेबल मॉडिफ़ायर फ़ैक्ट्री का इस्तेमाल करके कस्टम मॉडिफ़ायर बनाना
मौजूदा मॉडिफ़ायर को वैल्यू पास करने के लिए, कंपोज़ेबल फ़ंक्शन का इस्तेमाल करके कस्टम मॉडिफ़ायर भी बनाया जा सकता है. इसे कंपोज़ेबल मॉडिफ़ायर फ़ैक्ट्री कहा जाता है.
मॉडिफ़ायर बनाने के लिए कंपोज़ेबल मॉडिफ़ायर फ़ैक्ट्री का इस्तेमाल करने से, आपको animate*AsState
और अन्य Compose state backed animation APIs जैसे ज़्यादा लेवल वाले कंपोज़ एपीआई इस्तेमाल करने की सुविधा भी मिलती है. उदाहरण के लिए, यहां दिए गए स्निपेट में एक ऐसा मॉडिफ़ायर दिखाया गया है जो चालू/बंद होने पर, ऐल्फ़ा में होने वाले बदलाव को ऐनिमेट करता है:
@Composable fun Modifier.fade(enable: Boolean): Modifier { val alpha by animateFloatAsState(if (enable) 0.5f else 1.0f) return this then Modifier.graphicsLayer { this.alpha = alpha } }
return graphicsLayer { this.alpha = alpha }
का इस्तेमाल करके भी किया जा सकता है.
अगर आपका कस्टम मॉडिफ़ायर, CompositionLocal
से डिफ़ॉल्ट वैल्यू देने का एक आसान तरीका है, तो इसे लागू करने का सबसे आसान तरीका, कंपोज़ेबल मॉडिफ़ायर फ़ैक्ट्री का इस्तेमाल करना है:
@Composable fun Modifier.fadedBackground(): Modifier { val color = LocalContentColor.current return this then Modifier.background(color.copy(alpha = 0.5f)) }
इस तरीके में कुछ कमियां हैं. इनके बारे में यहां बताया गया है.
CompositionLocal
वैल्यू, मॉडिफ़ायर फ़ैक्ट्री की कॉल साइट पर तय की जाती हैं
कंपोज़ेबल मॉडिफ़ायर फ़ैक्ट्री का इस्तेमाल करके कस्टम मॉडिफ़ायर बनाते समय, कंपोज़िशन लोकल, कंपोज़िशन ट्री से वैल्यू लेते हैं. कंपोज़िशन ट्री में ही उन्हें बनाया जाता है, इस्तेमाल नहीं किया जाता. इस वजह से, उम्मीद से अलग नतीजे मिल सकते हैं. उदाहरण के लिए, कंपोज़िशन लोकल मॉडिफ़ायर का वह उदाहरण देखें जिसे हमने पहले बताया था. अब इसे कंपोज़ेबल फ़ंक्शन का इस्तेमाल करके, थोड़ा अलग तरीके से लागू किया गया है:
@Composable fun Modifier.myBackground(): Modifier { val color = LocalContentColor.current return this then Modifier.background(color.copy(alpha = 0.5f)) } @Composable fun MyScreen() { CompositionLocalProvider(LocalContentColor provides Color.Green) { // Background modifier created with green background val backgroundModifier = Modifier.myBackground() // LocalContentColor updated to red CompositionLocalProvider(LocalContentColor provides Color.Red) { // Box will have green background, not red as expected. Box(modifier = backgroundModifier) } } }
अगर आपको लगता है कि मॉडिफ़ायर को इस तरह से काम नहीं करना चाहिए, तो इसके बजाय कस्टम Modifier.Node
का इस्तेमाल करें. ऐसा इसलिए, क्योंकि कंपोज़िशन लोकल को इस्तेमाल की जा रही साइट पर सही तरीके से हल किया जाएगा और उन्हें सुरक्षित तरीके से ऊपर ले जाया जा सकता है.
कंपोज़ेबल फ़ंक्शन मॉडिफ़ायर कभी भी नहीं छोड़े जाते
कंपोज़ेबल फ़ैक्ट्री मॉडिफ़ायर को कभी भी स्किप नहीं किया जाता, क्योंकि रिटर्न वैल्यू वाले कंपोज़ेबल फ़ंक्शन को स्किप नहीं किया जा सकता. इसका मतलब है कि आपके मॉडिफ़ायर फ़ंक्शन को हर बार रीडीकंपोज़िशन पर कॉल किया जाएगा. अगर यह बार-बार रीडीकंपोज़ होता है, तो यह महंगा हो सकता है.
ऐप्लिकेशन बनाने की सुविधा देने वाले फ़ंक्शन के मॉडिफ़ायर को, ऐप्लिकेशन बनाने की सुविधा देने वाले फ़ंक्शन में कॉल किया जाना चाहिए
सभी कंपोज़ेबल फ़ंक्शन की तरह, कंपोज़ेबल फ़ैक्ट्री मॉडिफ़ायर को कंपोज़िशन के अंदर से कॉल किया जाना चाहिए. इससे यह तय होता है कि किसी मॉडिफ़ायर को कहां तक ले जाया जा सकता है. ऐसा इसलिए, क्योंकि इसे कंपोज़िशन से बाहर कभी भी नहीं ले जाया जा सकता. इसके उलट, कंपोज़ेबल फ़ंक्शन से बाहर नॉन-कंपोज़ेबल मॉडिफ़ायर फ़ैक्ट्री को होस्ट किया जा सकता है. इससे उन्हें आसानी से फिर से इस्तेमाल किया जा सकता है और परफ़ॉर्मेंस को बेहतर बनाया जा सकता है:
val extractedModifier = Modifier.background(Color.Red) // Hoisted to save allocations @Composable fun Modifier.composableModifier(): Modifier { val color = LocalContentColor.current.copy(alpha = 0.5f) return this then Modifier.background(color) } @Composable fun MyComposable() { val composedModifier = Modifier.composableModifier() // Cannot be extracted any higher }
Modifier.Node
का इस्तेमाल करके, कस्टम मॉडिफ़ायर के व्यवहार को लागू करना
Modifier.Node
, Compose में मॉडिफ़ायर बनाने के लिए एक लोअर लेवल एपीआई है. यह वही एपीआई है जिसमें Compose अपने मॉडिफ़ायर लागू करता है. साथ ही, कस्टम मॉडिफ़ायर बनाने का सबसे बेहतर तरीका है.
Modifier.Node
का इस्तेमाल करके कस्टम मॉडिफ़ायर लागू करना
Modifier.Node का इस्तेमाल करके कस्टम मॉडिफ़ायर लागू करने के तीन हिस्से होते हैं:
Modifier.Node
लागू करने की सुविधा, जिसमें आपके मॉडिफ़ायर का लॉजिक और स्थिति शामिल होती है.- एक
ModifierNodeElement
, जो मॉडिफ़ायर नोड इंस्टेंस बनाता है और उन्हें अपडेट करता है. - मॉडिफ़ायर फ़ैक्ट्री, जैसा कि पहले बताया गया है.
ModifierNodeElement
क्लास स्टेटलेस होती हैं और हर बार रीकंपोज़िशन होने पर, नए इंस्टेंस असाइन किए जाते हैं. वहीं, Modifier.Node
क्लास स्टेटफ़ुल हो सकती हैं और कई बार रीकंपोज़िशन होने पर भी बनी रहती हैं. साथ ही, इनका फिर से इस्तेमाल भी किया जा सकता है.
यहां दिए गए सेक्शन में, हर हिस्से के बारे में बताया गया है. साथ ही, एक सर्कल बनाने के लिए कस्टम मॉडिफ़ायर बनाने का उदाहरण दिखाया गया है.
Modifier.Node
Modifier.Node
लागू करने पर (इस उदाहरण में, CircleNode
), आपके कस्टम मॉडिफ़ायर की सुविधा लागू होती है.
// Modifier.Node private class CircleNode(var color: Color) : DrawModifierNode, Modifier.Node() { override fun ContentDrawScope.draw() { drawCircle(color) } }
इस उदाहरण में, सर्कल को उस रंग से बनाया गया है जिसे मॉडिफ़ायर फ़ंक्शन में पास किया गया है.
कोई नोड, Modifier.Node
के साथ-साथ शून्य या उससे ज़्यादा नोड टाइप लागू करता है. मॉडिफ़ायर को जिस फ़ंक्शन की ज़रूरत होती है उसके आधार पर, अलग-अलग नोड टाइप होते हैं. ऊपर दिए गए उदाहरण में, ड्रॉ करने की सुविधा होनी चाहिए. इसलिए, यह DrawModifierNode
को लागू करता है. इससे ड्रॉ करने के तरीके को ओवरराइड किया जा सकता है.
ये टाइप उपलब्ध हैं:
नोड |
इस्तेमाल |
सैंपल लिंक |
एक |
||
एक |
||
इस इंटरफ़ेस को लागू करने से, आपका |
||
एक |
||
एक |
||
एक |
||
एक |
||
ऐसा |
||
|
||
एक इससे कई नोड को एक साथ लागू करने में मदद मिल सकती है. |
||
इसकी मदद से, |
जब नोड से जुड़े एलिमेंट को अपडेट किया जाता है, तो नोड अपने-आप अमान्य हो जाते हैं. हमारा उदाहरण एक DrawModifierNode
है. इसलिए, जब भी एलिमेंट पर कोई टाइम अपडेट होता है, तो नोड फिर से रेंडर होता है और उसका रंग सही तरीके से अपडेट होता है. नोड के अपने-आप अमान्य होने की सुविधा से ऑप्ट आउट करना सेक्शन में दिए गए तरीके से, अपने-आप अमान्य होने की सुविधा से ऑप्ट आउट किया जा सकता है.
ModifierNodeElement
ModifierNodeElement
एक ऐसी क्लास है जिसमें बदलाव नहीं किया जा सकता. इसमें कस्टम मॉडिफ़ायर बनाने या अपडेट करने के लिए डेटा होता है:
// ModifierNodeElement private data class CircleElement(val color: Color) : ModifierNodeElement<CircleNode>() { override fun create() = CircleNode(color) override fun update(node: CircleNode) { node.color = color } }
ModifierNodeElement
को लागू करने के लिए, इन तरीकों को बदलना होगा:
create
: यह फ़ंक्शन, आपके मॉडिफ़ायर नोड को इंस्टैंशिएट करता है. जब पहली बार आपका मॉडिफ़ायर लागू होता है, तब नोड बनाने के लिए इस फ़ंक्शन को कॉल किया जाता है. आम तौर पर, इसका मतलब नोड बनाना और उसे उन पैरामीटर के साथ कॉन्फ़िगर करना होता है जो मॉडिफ़ायर फ़ैक्ट्री को पास किए गए थे.update
: इस फ़ंक्शन को तब कॉल किया जाता है, जब इस नोड में पहले से मौजूद जगह पर यह मॉडिफ़ायर दिया जाता है. हालांकि, इस दौरान प्रॉपर्टी में बदलाव होता है. यह क्लास केequals
तरीके से तय होता है. पहले से बनाए गए मॉडिफ़ायर नोड कोupdate
कॉल में पैरामीटर के तौर पर भेजा जाता है. इस समय, आपको नोड की प्रॉपर्टी अपडेट करनी चाहिए, ताकि वे अपडेट किए गए पैरामीटर से मेल खाएं. नोड को इस तरह से फिर से इस्तेमाल करने की सुविधा,Modifier.Node
की परफ़ॉर्मेंस को बेहतर बनाने में अहम भूमिका निभाती है. इसलिए, आपकोModifier.Node
के तरीके में नया नोड बनाने के बजाय, मौजूदा नोड को अपडेट करना होगा.update
सर्कल के उदाहरण में, नोड का रंग अपडेट किया गया है.
इसके अलावा, ModifierNodeElement
को equals
और hashCode
भी लागू करना होगा. update
को सिर्फ़ तब कॉल किया जाएगा, जब पिछले एलिमेंट के साथ तुलना करने पर 'बराबर है' फ़ंक्शन का नतीजा गलत हो.
ऊपर दिए गए उदाहरण में, इस काम के लिए डेटा क्लास का इस्तेमाल किया गया है. इन तरीकों का इस्तेमाल यह देखने के लिए किया जाता है कि किसी नोड को अपडेट करने की ज़रूरत है या नहीं. अगर आपके एलिमेंट में ऐसी प्रॉपर्टी हैं जिनसे यह तय नहीं होता कि किसी नोड को अपडेट करने की ज़रूरत है या नहीं या आपको बाइनरी कंपैटिबिलिटी की वजहों से डेटा क्लास का इस्तेमाल नहीं करना है, तो equals
और hashCode
को मैन्युअल तरीके से लागू किया जा सकता है. उदाहरण के लिए, पैडिंग मॉडिफ़ायर एलिमेंट.
मॉडिफ़ायर फ़ैक्ट्री
यह आपके मॉडिफ़ायर का सार्वजनिक एपीआई है. लागू की जाने वाली ज़्यादातर कार्रवाइयों से, मॉडिफ़ायर एलिमेंट बनता है और उसे मॉडिफ़ायर चेन में जोड़ा जाता है:
// Modifier factory fun Modifier.circle(color: Color) = this then CircleElement(color)
पूरा उदाहरण
ये तीन हिस्से मिलकर, कस्टम मॉडिफ़ायर बनाते हैं. इससे Modifier.Node
एपीआई का इस्तेमाल करके, सर्कल बनाया जा सकता है:
// Modifier factory fun Modifier.circle(color: Color) = this then CircleElement(color) // ModifierNodeElement private data class CircleElement(val color: Color) : ModifierNodeElement<CircleNode>() { override fun create() = CircleNode(color) override fun update(node: CircleNode) { node.color = color } } // Modifier.Node private class CircleNode(var color: Color) : DrawModifierNode, Modifier.Node() { override fun ContentDrawScope.draw() { drawCircle(color) } }
Modifier.Node
का इस्तेमाल करने की सामान्य स्थितियां
Modifier.Node
की मदद से कस्टम मॉडिफ़ायर बनाते समय, आपको ये सामान्य समस्याएं आ सकती हैं.
कोई पैरामीटर नहीं
अगर आपके मॉडिफ़ायर में कोई पैरामीटर नहीं है, तो उसे कभी अपडेट करने की ज़रूरत नहीं होती. साथ ही, उसे डेटा क्लास होने की भी ज़रूरत नहीं होती. यहां एक ऐसे मॉडिफ़ायर को लागू करने का उदाहरण दिया गया है जो कंपोज़ेबल में तय की गई पैडिंग लागू करता है:
fun Modifier.fixedPadding() = this then FixedPaddingElement data object FixedPaddingElement : ModifierNodeElement<FixedPaddingNode>() { override fun create() = FixedPaddingNode() override fun update(node: FixedPaddingNode) {} } class FixedPaddingNode : LayoutModifierNode, Modifier.Node() { private val PADDING = 16.dp override fun MeasureScope.measure( measurable: Measurable, constraints: Constraints ): MeasureResult { val paddingPx = PADDING.roundToPx() val horizontal = paddingPx * 2 val vertical = paddingPx * 2 val placeable = measurable.measure(constraints.offset(-horizontal, -vertical)) val width = constraints.constrainWidth(placeable.width + horizontal) val height = constraints.constrainHeight(placeable.height + vertical) return layout(width, height) { placeable.place(paddingPx, paddingPx) } } }
कंपोज़िशन के स्थानीय लोगों का रेफ़रंस
Modifier.Node
मॉडिफ़ायर, Compose के स्टेटस ऑब्जेक्ट में हुए बदलावों को अपने-आप नहीं देखते. जैसे, CompositionLocal
. Modifier.Node
मॉडिफ़ायर का फ़ायदा यह है कि ये कंपोज़ेबल फ़ैक्ट्री की मदद से बनाए गए मॉडिफ़ायर से बेहतर होते हैं. ऐसा इसलिए, क्योंकि ये currentValueOf
का इस्तेमाल करके, कंपोज़िशन लोकल की वैल्यू को पढ़ सकते हैं. कंपोज़िशन लोकल की वैल्यू को उस जगह से पढ़ा जाता है जहां मॉडिफ़ायर का इस्तेमाल आपके यूज़र इंटरफ़ेस (यूआई) ट्री में किया जाता है, न कि उस जगह से जहां मॉडिफ़ायर को असाइन किया जाता है.
हालांकि, मॉडिफ़ायर नोड इंस्टेंस, स्थिति में हुए बदलावों को अपने-आप नहीं देखते. कंपोज़िशन लोकल में बदलाव होने पर, अपने-आप प्रतिक्रिया देने के लिए, स्कोप के अंदर इसकी मौजूदा वैल्यू पढ़ी जा सकती है:
DrawModifierNode
:ContentDrawScope
LayoutModifierNode
:MeasureScope
&IntrinsicMeasureScope
SemanticsModifierNode
:SemanticsPropertyReceiver
इस उदाहरण में, LocalContentColor
की वैल्यू के आधार पर बैकग्राउंड बनाया गया है. ContentDrawScope
स्नैपशॉट में हुए बदलावों को ट्रैक करता है. इसलिए, LocalContentColor
की वैल्यू बदलने पर यह अपने-आप फिर से रेंडर हो जाता है:
class BackgroundColorConsumerNode : Modifier.Node(), DrawModifierNode, CompositionLocalConsumerModifierNode { override fun ContentDrawScope.draw() { val currentColor = currentValueOf(LocalContentColor) drawRect(color = currentColor) drawContent() } }
स्कोप से बाहर के स्टेट में हुए बदलावों पर प्रतिक्रिया देने और अपने मॉडिफ़ायर को अपने-आप अपडेट करने के लिए, ObserverModifierNode
का इस्तेमाल करें.
उदाहरण के लिए, Modifier.scrollable
इस तकनीक का इस्तेमाल करके, LocalDensity
में होने वाले बदलावों पर नज़र रखता है. यहां एक आसान उदाहरण दिया गया है:
class ScrollableNode : Modifier.Node(), ObserverModifierNode, CompositionLocalConsumerModifierNode { // Place holder fling behavior, we'll initialize it when the density is available. val defaultFlingBehavior = DefaultFlingBehavior(splineBasedDecay(UnityDensity)) override fun onAttach() { updateDefaultFlingBehavior() observeReads { currentValueOf(LocalDensity) } // monitor change in Density } override fun onObservedReadsChanged() { // if density changes, update the default fling behavior. updateDefaultFlingBehavior() } private fun updateDefaultFlingBehavior() { val density = currentValueOf(LocalDensity) defaultFlingBehavior.flingDecay = splineBasedDecay(density) } }
मॉडिफ़ायर को ऐनिमेट करना
Modifier.Node
लागू करने वाले लोगों के पास coroutineScope
का ऐक्सेस होता है. इससे Compose Animatable API का इस्तेमाल किया जा सकता है. उदाहरण के लिए, यह स्निपेट, पहले दिखाए गए CircleNode
में बदलाव करता है, ताकि वह बार-बार फ़ेड इन और फ़ेड आउट हो:
class CircleNode(var color: Color) : Modifier.Node(), DrawModifierNode { private lateinit var alpha: Animatable<Float, AnimationVector1D> override fun ContentDrawScope.draw() { drawCircle(color = color, alpha = alpha.value) drawContent() } override fun onAttach() { alpha = Animatable(1f) coroutineScope.launch { alpha.animateTo( 0f, infiniteRepeatable(tween(1000), RepeatMode.Reverse) ) { } } } }
डेलिगेशन का इस्तेमाल करके, मॉडिफ़ायर के बीच स्थिति शेयर करना
Modifier.Node
मॉडिफ़ायर, अन्य नोड को असाइन किए जा सकते हैं. इसके कई इस्तेमाल के उदाहरण हैं. जैसे, अलग-अलग मॉडिफ़ायर में सामान्य तौर पर लागू होने वाली चीज़ों को अलग करना. हालांकि, इसका इस्तेमाल मॉडिफ़ायर के बीच सामान्य स्थिति को शेयर करने के लिए भी किया जा सकता है.
उदाहरण के लिए, क्लिक किए जा सकने वाले मॉडिफ़ायर नोड को लागू करने का एक बुनियादी तरीका, जो इंटरैक्शन डेटा शेयर करता है:
class ClickableNode : DelegatingNode() { val interactionData = InteractionData() val focusableNode = delegate( FocusableNode(interactionData) ) val indicationNode = delegate( IndicationNode(interactionData) ) }
नोड के अपने-आप अमान्य होने की सुविधा से ऑप्ट आउट करना
Modifier.Node
कॉल अपडेट होने पर, Modifier.Node
नोड अपने-आप अमान्य हो जाते हैं.ModifierNodeElement
ज़्यादा जटिल मॉडिफ़ायर के लिए, हो सकता है कि आप इस सुविधा से ऑप्ट आउट करना चाहें, ताकि आपको यह तय करने का ज़्यादा कंट्रोल मिल सके कि मॉडिफ़ायर कब चरणों को अमान्य करता है.
यह खास तौर पर तब मददगार होता है, जब कस्टम मॉडिफ़ायर, लेआउट और ड्रॉ, दोनों में बदलाव करता हो. अपने-आप अमान्य होने की सुविधा से ऑप्ट आउट करने पर, सिर्फ़ ड्रॉ से जुड़ी प्रॉपर्टी, जैसे कि color
में बदलाव होने पर ही ड्रॉ को अमान्य किया जा सकता है. इससे लेआउट अमान्य नहीं होता और आपके मॉडिफ़ायर की परफ़ॉर्मेंस बेहतर हो सकती है.
इसका एक काल्पनिक उदाहरण यहां दिया गया है. इसमें एक ऐसा मॉडिफ़ायर दिखाया गया है जिसमें color
, size
, और onClick
लैम्डा को प्रॉपर्टी के तौर पर इस्तेमाल किया गया है. यह मॉडिफ़ायर, सिर्फ़ ज़रूरी चीज़ों को अमान्य करता है. साथ ही, गैर-ज़रूरी चीज़ों को अमान्य नहीं करता:
class SampleInvalidatingNode( var color: Color, var size: IntSize, var onClick: () -> Unit ) : DelegatingNode(), LayoutModifierNode, DrawModifierNode { override val shouldAutoInvalidate: Boolean get() = false private val clickableNode = delegate( ClickablePointerInputNode(onClick) ) fun update(color: Color, size: IntSize, onClick: () -> Unit) { if (this.color != color) { this.color = color // Only invalidate draw when color changes invalidateDraw() } if (this.size != size) { this.size = size // Only invalidate layout when size changes invalidateMeasurement() } // If only onClick changes, we don't need to invalidate anything clickableNode.update(onClick) } override fun ContentDrawScope.draw() { drawRect(color) } override fun MeasureScope.measure( measurable: Measurable, constraints: Constraints ): MeasureResult { val size = constraints.constrain(size) val placeable = measurable.measure(constraints) return layout(size.width, size.height) { placeable.place(0, 0) } } }