Compose มีตัวปรับแต่งมากมายสำหรับลักษณะการทำงานทั่วไปที่พร้อมใช้งาน แต่คุณก็สร้างตัวปรับแต่งที่กำหนดเองได้เช่นกัน
ตัวปรับแต่งมีหลายส่วนดังนี้
- โรงงานตัวปรับแต่ง
- นี่คือฟังก์ชันส่วนขยายใน
Modifierซึ่งมี API ที่เป็นสำนวนสำหรับตัวปรับแต่งและอนุญาตให้เชื่อมโยงตัวปรับแต่งเข้าด้วยกัน โรงงานตัวปรับแต่งจะสร้างองค์ประกอบตัวปรับแต่งที่ Compose ใช้เพื่อปรับเปลี่ยน UI
- นี่คือฟังก์ชันส่วนขยายใน
- องค์ประกอบตัวปรับแต่ง
- คุณสามารถติดตั้งใช้งานลักษณะการทำงานของตัวปรับแต่งได้ที่นี่
คุณสามารถติดตั้งใช้งานตัวปรับแต่งที่กำหนดเองได้หลายวิธี ขึ้นอยู่กับฟังก์ชันการทำงานที่ต้องการ โดยส่วนใหญ่วิธีที่ง่ายที่สุดในการติดตั้งใช้งานตัวปรับแต่งที่กำหนดเองคือการติดตั้งใช้งานโรงงานตัวปรับแต่งที่กำหนดเองซึ่งรวมโรงงานตัวปรับแต่งอื่นๆ ที่กำหนดไว้แล้ว หากต้องการลักษณะการทำงานที่กำหนดเองเพิ่มเติม ให้ติดตั้งใช้งานองค์ประกอบตัวปรับแต่งโดยใช้ Modifier.Node API ซึ่งเป็น 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)
สร้างตัวปรับแต่งที่กำหนดเองโดยใช้โรงงานตัวปรับแต่งที่ประกอบกันได้
นอกจากนี้ คุณยังสร้างตัวปรับแต่งที่กำหนดเองได้โดยใช้ฟังก์ชันที่ประกอบกันได้เพื่อส่งค่าไปยังตัวปรับแต่งที่มีอยู่ ซึ่งเรียกว่าโรงงานตัวปรับแต่งที่ประกอบกันได้
การใช้โรงงานตัวปรับแต่งที่ประกอบกันได้เพื่อสร้างตัวปรับแต่งยังช่วยให้คุณใช้ Compose API ระดับสูงขึ้นได้ เช่น animate*AsState และ API ภาพเคลื่อนไหวอื่นๆ ที่สนับสนุนโดยสถานะ 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 จะได้รับการแก้ไขที่ตำแหน่งการเรียกของโรงงานตัวปรับแต่ง
เมื่อสร้างตัวปรับแต่งที่กำหนดเองโดยใช้โรงงานตัวปรับแต่งที่ประกอบกันได้ ค่าของ Composition Local จะมาจากแผนผังการประกอบที่สร้างขึ้น ไม่ใช่ที่ใช้ ซึ่งอาจทำให้เกิดผลลัพธ์ที่ไม่คาดคิด ตัวอย่างเช่น ลองดูตัวอย่างตัวปรับแต่ง Composition Local ที่กล่าวถึงก่อนหน้านี้ ซึ่งติดตั้งใช้งานแตกต่างกันเล็กน้อยโดยใช้ฟังก์ชันที่ประกอบกันได้ดังนี้
@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ที่กำหนดเองแทน เนื่องจากระบบจะแก้ปัญหา Composition Local อย่างถูกต้องที่ตำแหน่งการใช้งานและสามารถยกขึ้นได้อย่างปลอดภัย
ระบบจะไม่ข้ามตัวปรับแต่งฟังก์ชันที่ประกอบกันได้
ระบบจะไม่ข้ามตัวปรับแต่งโรงงานที่ประกอบกันได้เนื่องจากฟังก์ชันที่ประกอบกันได้ ซึ่งมีค่าที่แสดงผลจะข้ามไม่ได้ ซึ่งหมายความว่าระบบจะเรียกใช้ฟังก์ชันตัวปรับแต่งทุกครั้งที่มีการประกอบใหม่ ซึ่งอาจใช้ทรัพยากรมากหากมีการประกอบใหม่บ่อยๆ
ต้องเรียกใช้ตัวปรับแต่งฟังก์ชันที่ประกอบกันได้ภายในฟังก์ชันที่ประกอบกันได้
ตัวปรับแต่งโรงงานที่ประกอบกันได้ต้องเรียกใช้จากการประกอบภายใน เช่นเดียวกับฟังก์ชันที่ประกอบกันได้ทั้งหมด ซึ่งจะจำกัดตำแหน่งที่สามารถยกตัวปรับแต่งขึ้นได้ เนื่องจากตัวปรับแต่งจะยกขึ้นจากการประกอบไม่ได้ ในทางตรงกันข้าม โรงงานตัวปรับแต่งที่ไม่ประกอบกันได้สามารถยกขึ้นจากฟังก์ชันที่ประกอบกันได้เพื่อให้ใช้ซ้ำได้ง่ายขึ้นและปรับปรุงประสิทธิภาพดังนี้
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 เป็น API ระดับล่างสำหรับการสร้างตัวปรับแต่งใน Compose ซึ่งเป็น API เดียวกันที่ Compose ใช้ติดตั้งใช้งานตัวปรับแต่งของตัวเอง และเป็นวิธีที่มีประสิทธิภาพสูงสุดในการสร้างตัวปรับแต่งที่กำหนดเอง
ติดตั้งใช้งานตัวปรับแต่งที่กำหนดเองโดยใช้ Modifier.Node
การติดตั้งใช้งานตัวปรับแต่งที่กำหนดเองโดยใช้ Modifier.Node มี 3 ส่วนดังนี้
- การติดตั้งใช้งาน
Modifier.Nodeที่มีตรรกะและ สถานะของตัวปรับแต่ง - A
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 รวมถึงประเภทโหนดตั้งแต่ 0 ประเภทขึ้นไป โดยมีประเภทโหนดต่างๆ ขึ้นอยู่กับฟังก์ชันการทำงานที่ตัวปรับแต่งต้องการ ตัวอย่างก่อนหน้าต้องวาดได้ จึงติดตั้งใช้งาน 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 กับองค์ประกอบก่อนหน้าแสดงผลเป็นเท็จ
ตัวอย่างก่อนหน้าใช้คลาสข้อมูลเพื่อให้ดำเนินการนี้ ระบบจะใช้เมธอดเหล่านี้เพื่อตรวจสอบว่าต้องอัปเดตโหนดหรือไม่ หากองค์ประกอบมีพร็อพเพอร์ตี้ที่
ไม่ได้มีส่วนช่วยในการพิจารณาว่าต้องอัปเดตโหนดหรือไม่ หรือคุณต้องการหลีกเลี่ยง
คลาสข้อมูลด้วยเหตุผลด้านความเข้ากันได้แบบไบนารี คุณสามารถติดตั้งใช้งาน
equals และ hashCode ด้วยตนเองได้ เช่น
องค์ประกอบตัวปรับแต่งการเพิ่มระยะห่างภายใน
โรงงานตัวปรับแต่ง
นี่คือพื้นผิว API สาธารณะของตัวปรับแต่ง การติดตั้งใช้งานส่วนใหญ่จะสร้างองค์ประกอบตัวปรับแต่งและเพิ่มลงในการเชื่อมโยงตัวปรับแต่งดังนี้
// Modifier factory fun Modifier.circle(color: Color) = this then CircleElement(color)
ตัวอย่างที่สมบูรณ์
ทั้ง 3 ส่วนนี้รวมกันเพื่อสร้างตัวปรับแต่งที่กำหนดเองเพื่อวาดวงกลมโดยใช้ Modifier.Node API ดังนี้
// 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) } } }
อ้างอิง Composition Local
ตัวปรับแต่ง Modifier.Node จะไม่สังเกตการเปลี่ยนแปลงออบเจ็กต์สถานะ Compose เช่น CompositionLocal โดยอัตโนมัติ ข้อดีของตัวปรับแต่ง Modifier.Node เหนือตัวปรับแต่งที่สร้างขึ้นด้วย Factory ที่ประกอบกันได้คือ ตัวปรับแต่งสามารถอ่านค่าของ Composition Local จากตำแหน่งที่ใช้ตัวปรับแต่งในแผนผัง UI ไม่ใช่ตำแหน่งที่จัดสรรตัวปรับแต่ง โดยใช้ currentValueOf
อย่างไรก็ตาม อินสแตนซ์โหนดตัวปรับแต่งจะไม่สังเกตการเปลี่ยนแปลงสถานะโดยอัตโนมัติ หากต้องการตอบสนองต่อการเปลี่ยนแปลง Composition Local โดยอัตโนมัติ คุณสามารถอ่านค่าปัจจุบันภายในขอบเขตได้ดังนี้
DrawModifierNode:ContentDrawScopeLayoutModifierNode:MeasureScope&IntrinsicMeasureScopeSemanticsModifierNode: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 จะทำให้ตัวเองไม่ถูกต้องโดยอัตโนมัติเมื่อ 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) } } }