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