कस्टम मॉडिफ़ायर बनाएं

Compose में सामान्य व्यवहार के लिए कई मॉडिफ़ायर पहले से मौजूद हैं, हालांकि, अपने हिसाब से कस्टम मॉडिफ़ायर भी बनाए जा सकते हैं.

मॉडिफ़ायर के कई हिस्से होते हैं:

  • कार्रवाई बदलने वाली फ़ैक्ट्री
    • यह Modifier पर मौजूद एक एक्सटेंशन फ़ंक्शन है, जो एक idiomatic API देता है जोड़ा जा सकता है. साथ ही, इससे मॉडिफ़ायर को आसानी से एक साथ जोड़ा जा सकता है. कॉन्टेंट बनाने मॉडिफ़ायर फ़ैक्ट्री, बदलाव करने के लिए वे एलिमेंट बनाता है जिनका इस्तेमाल Compose में बदलाव करने के लिए किया जाता है आपका यूज़र इंटरफ़ेस (यूआई)
  • कार्रवाई बदलने वाली चीज़
    • यहां पर, मॉडिफ़ायर का व्यवहार लागू किया जा सकता है.

कस्टम मॉडिफ़ायर लागू करने के कई तरीके हैं. ये तरीके कुछ सुविधाएं चाहिए. अक्सर, कस्टम संशोधक को लागू करने का सबसे आसान तरीका यह है सिर्फ़ कस्टम मॉडिफ़ायर फ़ैक्ट्री लागू करने के लिए, जो पहले से तय अन्य कार्रवाई बदलने वाली फ़ैक्ट्री एक साथ. अगर आपको ज़्यादा कस्टम व्यवहार की ज़रूरत है, तो कार्रवाई बदलने वाली चीज़ Modifier.Node API का इस्तेमाल कर रही है, जो नीचे के लेवल की हैं लेकिन ज़्यादा सुविधाएं देते हैं.

मौजूदा मॉडिफ़ायर को एक साथ चेन करें

अक्सर मौजूदा कस्टम पैरामीटर का इस्तेमाल करके कस्टम मॉडिफ़ायर बनाया जा सकता है मॉडिफ़ायर हैं. उदाहरण के लिए, 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 स्टेट बैक अप ऐनिमेशन एपीआई. उदाहरण के लिए, नीचे दिया गया स्निपेट चालू/बंद होने पर ऐल्फ़ा बदलाव को ऐनिमेट करने वाला मॉडिफ़ायर:

@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 }
}

यदि आपका कस्टम संशोधक से डिफ़ॉल्ट मान प्रदान करने की सुविधा पद्धति है 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 को लागू करता है, जो इसे ड्रॉ करने के तरीके को बदलने की अनुमति देता है.

उपलब्ध टाइप यहां दिए गए हैं:

नोड

इस्तेमाल किए जाने से जुड़ी जानकारी

सैंपल लिंक

LayoutModifierNode

ऐसा Modifier.Node जो रैप किए गए कॉन्टेंट को मेज़र करने और उसके लेआउट में बदलाव करता है.

सैंपल

DrawModifierNode

लेआउट की जगह पर दिखने वाला Modifier.Node.

सैंपल

CompositionLocalConsumerModifierNode

इस इंटरफ़ेस को लागू करने से, आपका Modifier.Node कंपोज़िशन का डेटा पढ़ने की अनुमति देता है.

सैंपल

SemanticsModifierNode

एक ऐसा Modifier.Node जो टेस्टिंग, सुलभता, और इसी तरह के इस्तेमाल के उदाहरणों में इस्तेमाल के लिए सिमैंटिक कुंजी/वैल्यू जोड़ता है.

सैंपल

PointerInputModifierNode

ऐसा Modifier.Node जिसे Pointerइनपुटबदलाव मिलता है.

सैंपल

ParentDataModifierNode

एक Modifier.Node जो पैरंट लेआउट के लिए डेटा उपलब्ध कराता है.

सैंपल

LayoutAwareModifierNode

Modifier.Node, जिसे onMeasured और onPlaced कॉलबैक मिलते हैं.

सैंपल

GlobalPositionAwareModifierNode

एक Modifier.Node, जिसे आखिरी LayoutCoordinates लेआउट के साथ onGloballyPositioned कॉलबैक मिलता है. ऐसा तब होता है, जब कॉन्टेंट की ग्लोबल पोज़िशन बदल जाती है.

सैंपल

ObserverModifierNode

ObserverNode को लागू करने वाले Modifier.Node, onObservedReadsChanged को खुद ही लागू कर सकते हैं. किसी observeReads ब्लॉक में, स्नैपशॉट ऑब्जेक्ट में किए गए बदलावों के जवाब में कॉल किया जाएगा.

सैंपल

DelegatingNode

Modifier.Node, जो अन्य Modifier.Node इंस्टेंस को काम सौंप सकता है.

कई नोड इंप्लीमेंटेशन को एक साथ जोड़ने के लिए यह उपयोगी हो सकता है.

सैंपल

TraversableNode

एक ही तरह की या किसी खास कुंजी के लिए, Modifier.Node क्लास को नोड ट्री को अप/डाउन करने की अनुमति देता है.

सैंपल

जब नोड से जुड़े अपडेट को लागू किया जाता है, तो वे अपने-आप अमान्य हो जाते हैं एलिमेंट. हमारा उदाहरण 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 लागू करने के तरीके को इन तरीकों को बदलना होगा:

  1. create: यह वह फ़ंक्शन है जो आपके मॉडिफ़ायर नोड को इंस्टैंशिएट करता है. यह हो जाता है जब आपके मॉडिफ़ायर को पहली बार लागू किया जाता है, तो नोड बनाने के लिए इसका इस्तेमाल किया जाता है. आम तौर पर, नोड को बनाने और उसे उन पैरामीटर के साथ कॉन्फ़िगर करने पर लागू होता है को मॉडिफ़ायर फ़ैक्ट्री में पास किया गया था.
  2. update: जब भी इस मॉडिफ़ायर को इसमें दिया जाता है, तो यह फ़ंक्शन कॉल किया जाता है यही नोड पहले से मौजूद है, लेकिन प्रॉपर्टी बदल गई है. यह है क्लास के equals तरीके से तय किया जाता है. कार्रवाई बदलने वाला नोड जो था पहले बनाया गया डेटा update कॉल में पैरामीटर के तौर पर भेजा जाता है. इस स्थिति में, आपको नोड अपडेट करने चाहिए' प्रॉपर्टी जो अपडेट की गई हैं पैरामीटर का इस्तेमाल करें. नोड का इस तरह से फिर से इस्तेमाल करने की क्षमता 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 मॉडिफ़ायर, कंपोज़ की स्थिति में होने वाले बदलावों को अपने-आप नहीं देखते हैं ऑब्जेक्ट, जैसे कि CompositionLocal. Modifier.Node मॉडिफ़ायर का फ़ायदा इससे ज़्यादा है कंपोज़ेबल फ़ैक्ट्री की मदद से बनाए गए मॉडिफ़ायर का इस्तेमाल करके, उस कंपोज़िशन की स्थानीय वैल्यू जहां से आपके यूज़र इंटरफ़ेस (यूआई) में मॉडिफ़ायर का इस्तेमाल किया गया है ट्री, न कि जहां मॉडिफ़ायर असाइन किया गया है. currentValueOf का इस्तेमाल करके ऐसा किया जा सकता है.

हालांकि, मॉडिफ़ायर नोड इंस्टेंस से स्थिति में होने वाले बदलाव अपने-आप नहीं दिखते. यहां की यात्रा पर हूं कंपोज़िशन में होने वाले बदलावों पर अपने-आप प्रतिक्रिया देता है, तो दायरे के अंदर मान:

यह उदाहरण, बैकग्राउंड के आधार पर ड्रॉ करने के लिए 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 का ऐक्सेस होता है. इससे आपको कंपोज़ की सुविधा वाले एपीआई का इस्तेमाल करना होगा. उदाहरण के लिए, यह स्निपेट ऊपर से CircleNode बार-बार फ़ेड इन और आउट करने के लिए:

class CircleNode(var color: Color) : Modifier.Node(), DrawModifierNode {
    private val alpha = Animatable(1f)

    override fun ContentDrawScope.draw() {
        drawCircle(color = color, alpha = alpha.value)
        drawContent()
    }

    override fun onAttach() {
        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 नोड उनसे जुड़े होते हैं, तो वे अपने-आप अमान्य हो जाते हैं ModifierNodeElement कॉल अपडेट किए गए. कभी-कभी, ज़्यादा जटिल मॉडिफ़ायर में, आप इस व्यवहार से ऑप्ट आउट करना चाहते हैं और कब आपका मॉडिफ़ायर, फ़ेज़ को अमान्य कर देता है.

यह खास तौर पर तब फ़ायदेमंद हो सकता है, जब आपका कस्टम मॉडिफ़ायर, लेआउट और ड्रॉ करें. अपने-आप अमान्य होने की सुविधा से ऑप्ट-आउट करने पर, ड्रॉ की अमान्य प्रोसेस तब की जा सकती है, जब सिर्फ़ ड्रॉ से जुड़ी प्रॉपर्टी, जैसे कि color, लेआउट को बदलता है, और उसे अमान्य नहीं करता है. इससे आपके मॉडिफ़ायर की परफ़ॉर्मेंस बेहतर हो सकती है.

इसका एक काल्पनिक उदाहरण नीचे एक ऐसे मॉडिफ़ायर के साथ दिखाया गया है जिसमें color, प्रॉपर्टी के तौर पर, size और onClick lambda को. यह मॉडिफ़ायर सिर्फ़ उसी जानकारी को अमान्य करता है जो ज़रूरी है. साथ ही, किसी भी अमान्य ऐसी जानकारी को स्किप कर देता है जो:

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)
        }
    }
}