Modifier — สายโซ่ตัวแก้ไข และประสิทธิภาพใน Compose

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-06-28 เวลาอ่าน: 8 นาที

Modifier คืออ็อบเจกต์ที่ไม่สามารถเปลี่ยนแปลงได้ใน Jetpack Compose ซึ่งกำหนดคุณสมบัติขององค์ประกอบ UI: ขนาด ระยะประกาด พื้นหลัง การจัดการท่าทางและพฤติกรรม ตัวแก้ไขจะถูกรวมเข้าเป็นสายโซ่ผ่านการเรียกเรียงลำดับ และลำดับการใช้งานของพวกมันมีผลต่อผลลัพธ์อย่างมาก ตามแหล่งข้อมูล Google Android Developers, 2026 การใช้ Modifier อย่างถูกต้องเป็นรากฐานของการสร้างอินเทอร์เฟสที่ยืดหยุ่นและมีประสิทธิภาพใน UI รูปแบบแสดงผล

หัวข้อสำคัญ

  • Modifier คืออ็อบเจกต์ที่ไม่สามารถเปลี่ยนแปลงได้ซึ่งอธิบายลักษณะและพฤติกรรมขององค์ประกอบ UI
  • สายโซ่ ตัวแก้ไขถูกสร้างเรียงลำดับ ลำดับมีผลต่อการแสดงผล
  • ลำดับ มีความสำคัญ: padding → size แตกต่างจาก size → padding
  • Modifier.composed ช่วยให้สร้างตัวแก้ไขผสมแบบกำหนดเองได้
  • การเพิ่มประสิทธิภาพ: หลีกเลี่ยงการสร้าง Modifier ใหม่ในทุกการประกอบใหม่

Modifier ใน Jetpack Compose คืออะไร

Modifier คืออินเทอร์เฟส์จากแพ็คเกจ androidx.compose.ui ที่ใช้รูปแบบ Composite แต่ละตัวแก้ไขคือองค์ประกอบของสายโซ่ที่ห่อหุ้มตัวก่อนหน้าและเพิ่มพฤติกรรมของตัวเอง Modifier เป็นอมมิตแบบไม่สามารถเปลี่ยนแปลงได้ — การเปลี่ยนแปลงใดๆ จะสร้างอ็อบเจกต์ใหม่โดยการคัดลอกและเพิ่มองค์ประกอบใหม่ลงในสายโซ่ ซึ่งช่วยให้สามารถแชร์ Modifier ดีวกันหลายองค์ประกอบได้อย่างปลอดภัย

ฟังก์ชันตัวแก้ไขพื้นฐานจะถูกเรียกผ่านอ็อบเจกต์คู่กับ Modifier (ตัวอย่าง: Modifier.padding(), Modifier.fillMaxWidth()) แต่ละฟังก์ชันจะส่งคืน Modifier ใหม่พร้อมกับองค์ประกอบที่เพิ่มเข้าไป หากมีหลายตัวแก้ไข พวกมันจะถูกรวมเข้าเป็นสายโซ่: Modifier.padding(16.dp).fillMaxWidth().background(Color.Blue) ลำดับเรียงจากด้านนอกไปสู่ด้านในเมื่อเทียบกับองค์ประกอบ UI

เมื่อเปรียบเทียบกับ View แบบดั้งเดิมที่คุณสมบัติถูกกำหนดผ่าน setter (view.setPadding(...), view.setBackground(...)) ใน Compose Modifier เป็นคำอธิบายแบบแสดงผล องค์ประกอบจะไม่นำตัวแก้ไขไปใช้ในขณะที่ทำงาน — LayoutNode จะเดินตามสายโซ่ Modifier ในระหว่างการประกอบและสร้างรายการ Modifier.Element ซึ่งจะถูกประมวลผลในขั้นตอนการวัดและการจัดวาง

สายโซ่ตัวแก้ไขและลำดับการใช้งาน

ลำดับ ของตัวแก้ไขเป็นหนึ่งในข้อผิดพลาดที่พบบ่อยที่สุดใน Compose แต่ละตัวแก้ไขจะห่อหุ้มตัวก่อนหน้าและการดำเนินการจะถูกใช้จากด้านนอกไปสู่ด้านใน ตัวอย่าง: padding(16.dp).clickable { }: แรกจะเพิ่มระยะประกาดรอบองค์ประกอบ จากนั้นพื้นที่คลิกจะรวมระยะประกาดด้วย clickable { }.padding(16.dp): พื้นที่คลิกจะเท่ากับขนาดขององค์ประกอบก่อน จากนั้นจึงเพิ่มระยะประกาดรอบรอบ — การคลิกบริเวณระยะประกาดจะไม่ทำงาน

กฎเก็บจำ: อ่านสายโซ่จากซ้ายไปขวาและใช้งานจากด้านนอกไปสู่ด้านใน ตัวแก้ไขตัวแรกคือตัวที่อยู่ด้านนอกมากที่สุด ใช้กับพื้นที่รอบององค์ประกอบ ตัวสุดท้ายคือตัวที่อยู่ด้านในมากที่สุด ใช้กับเนื้อหาโดยตรง ตัวแก้ไขด้านขนาด (size, fillMaxWidth) ควรมาหลังระยะประกาดหากต้องการระยะประกาดจากตัวแม่ หรือมาก่อนระยะประกาดหากต้องการให้เนื้อหาถูกจำกัดก่อนแล้วใส่กลาง

ตัวอย่าง: size(100.dp).padding(10.dp) — องค์ประกอบขนาดคงที่ 100dp จากนั้นมีระยะประกาด 10dp ด้านนอก (ขนาดสุดท้าย 120dp) padding(10.dp).size(100.dp) — ระยะประกาด 10dp ลดพื้นที่ว่างใช้งานเหลือ (ตัวแม่ - 20dp) จากนั้น size(100dp) อาจล้นตัวแม่ ควรคิดเพื่อให้ดีเกี่ยวกับลำดับอย่างรอบคอบ โดยใช้แบบทดสอบการแสดงผลเพื่อตรวจสอบผลลัพธ์

ลำดับผลลัพธ์
padding → clickableคลิกทำงานเสมอเพื้องระยะประกาด
clickable → paddingคลิกทำงานเฉพาะเนื้อหา ระยะประกาดเป็นโซนที่ตาย
size → paddingองค์ประกอบ size(100) ระยะประกาดด้านนอก → 100+2*pad
padding → sizeระยะประกาดลดพื้นที่ size อาจเกินขอบเขต
background → paddingพื้นหลังเต็มทั้งองค์ประกอบรวมถึงพื้นที่ด้านนอก
padding → backgroundพื้นหลังเฉพาะภายในระยะประกาด (พื้นที่ด้านนอกโปร่งใส)

ประเภทของตัวแก้ไข: ขนาด ระยะประกาด การตกแต่งและพฤติกรรม

ไลบรารีมาตรฐานของ Compose ประกอบด้วย ~50+ ตัวแก้ไขที่แบ่งออกเป็นหมวดหมู่ ขนาดและตำแหน่ง: Modifier.size(), width(), height(), fillMaxSize(), fillMaxWidth(), fillMaxHeight(), defaultMinSize(), requiredSize() ระยะประกาดและขอบ: padding(), offset(), margin (กำหนดผ่านระยะประกาดของตัวแม่หรือ Layout) การตกแต่ง: background(), border(), clip(), alpha(), shadow(), blur()

พฤติกรรมและท่าทาง: clickable(), combinedClickable(), pointerInput(), draggable(), swipeable() การจัดวางในคอนเทนเนอร์: weight() (สำหรับ Row/Column), align(), alignBy(), matchParentSize() ความหมายและการเข้าถึง: semantics(), testTag(), clearAndSetSemantics() การวาดภาพ: drawBehind(), drawWithContent(), drawModifier() — ตัวแก้ไขที่ช่วยให้วาดภาพแบบกำหนดเองบน canvas

ตัวแก้ไขเชิงความหมาย เป็นหมวดหมู่พิเศษ Modifier.semantics {} กำหนดว่าองค์ประกอบจะถูกแสดงอย่างไรในต้นไม้การเข้าถึง Compose จะเติมความหมายโดยอัตโนมัติจากข้อความ แต่สำหรับองค์ประกอบที่กำหนดเองจะต้องกำหนดบทบาท สถานะและการกระทำด้วยตนเอง ซึ่งสำคัญอย่างยิ่งสำหรับการปฏิบัติตาม WCAG 2.2 และการทำงานใน TalkBack (Android) และ VoiceOver (iOS)

kotlin
@Composable
fun ModifierDemo() {
    // สายโซ่ตัวแก้ไขที่มีลำดับที่ถูกต้อง
    Box(
        modifier = Modifier
            .size(150.dp)
            .padding(8.dp)
            .border(2.dp, Color.Gray)
            .background(Color(0xFFE3F2FD))
            .clickable { /* handle click */ }
            .semantics {
                contentDescription = "Demo card with click action"
                role = Role.Button
            }
    ) {
        Text("แตะต้องฉัน")
    }
}

การสร้างตัวแก้ไขแบบกำหนดเองผ่าน Modifier.composed

Modifier.composed คือเมธอดไฟเฟกเตอรี่ที่ช่วยให้สร้างตัวแก้ไขแบบผสมที่สามารถใช้ตัวแก้ไขอื่น LocalComposition และสถานะท้องถิ่น ต่างจากฟังก์ชันส่วนขยายทั่วไป composed จะสร้างอินสแตนซ์ทุกครั้งที่ใช้งาน ทำให้ตัวแก้ไขสามารถมีสถานะของตัวเองได้

เมื่อให้ใช้ composed: การรวมกันที่เกิดซ้ำ ของตัวแก้ไข (ตัวอย่าง: รูปแบบบัตรมาตรฐาน: padding + background + border + clickable); ตัวแก้ไขที่มีสถานะ (การเปลี่ยนพื้นหลังแบบเคลื่อนไหวเมื่อกด); การเข้าถึง CompositionLocals (โครงสี MaterialTheme, ความหนาแน่นพิกเซล) สำหรับกรณีทั่วไป ฟังก์ชันส่วนขยายทั่วไปที่ไม่มี composed ก็เพียงพอ

ประสิทธิภาพของ composed: แต่ละการเรียกจะสร้างอ็อบเจกต์ตัวแก้ไขใหม่ ซึ่งอาจทำให้เกิดการจัดสรรค์พิเศษเพิ่มในระหว่างการประกอบใหม่ เพื่อป้องกันสิ่งนี้ ให้ห่อ composed ไว้ใน remember Google แนะนำให้ใช้ composed เมื่อจำเป็นต้องใช้สถานะหรือ CompositionLocal ภายในเท่านั้น สำหรับการรวมแบบคงที่ ให้ใช้ฟังก์ชันส่วนขยายทั่วไป

kotlin
// ตัวแก้ไขแบบกำหนดเองผ่าน composed ที่มีสถานะ
fun Modifier.cardStyle(
    elevation: Dp = 4.dp,
    isSelected: Boolean = false
): Modifier = this.composed {
    val backgroundColor = if (isSelected)
        MaterialTheme.colorScheme.primaryContainer
    else
        MaterialTheme.colorScheme.surface

    this
        .fillMaxWidth()
        .padding(12.dp)
        .background(backgroundColor, RoundedCornerShape(8.dp))
        .shadow(elevation, RoundedCornerShape(8.dp))
}

// ตัวอย่างการใช้งาน
@Composable
fun CardList() {
    Column {
        Box(Modifier.cardStyle()) { Text("รายการที่ 1") }
        Box(Modifier.cardStyle(isSelected = true)) { Text("เลือกแล้ว") }
    }
}

// รุ่นคงที่ (ไม่มี composed) — เร็วกว่า
fun Modifier.simpleCardStyle(): Modifier =
    this.fillMaxWidth().padding(8.dp).clip(RoundedCornerShape(4.dp))

ประสิทธิภาพของ Modifier และแนวปฏิบัติที่ดีที่สุด

หลีกเลี่ยงการสร้าง Modifier ใหม่ ในทุกการประกอบใหม่ หากตัวแก้ไขไม่ขึ้นอยู่กับข้อมูลที่สามารถเปลี่ยนแปลงได้ — ย้ายไปยังค่าคงที่หรือ remember ทุกครั้งที่เรียก Modifier.padding().background() จะสร้างอ็อบเจกต์ Modifier.Element ใหม่ ในองค์ประกอบแบบแยกออกมาจะไม่มีผล แต่ใน LazyColumn ที่มีองค์ประกอบเป็นร้อย ๆ การจัดสรรค์พิเศษเพิ่มเติมจะทำให้เกิดการหน่วงในขณะเลื่อนเลือน

กฎ: หากสายโซ่ตัวแก้ไขไม่ขึ้นอยู่กับพารามิเตอร์ของฟังก์ชัน Composable — ประกาศเป็น val นอกฟังก์ชัน (ในระดับไฟล์หรือ Companion) หากขึ้นอยู่ — ใช้ remember(ตัวแปร) { ... } สำหรับตัวแก้ไขที่เหมือนกันอยู่เสมอ val นอก Composable มีประสิทธิภาพมากที่สุด: อ็อบเจกต์เหล่านี้จะถูกสร้างเพียงครั้งเดียวตลอดอายุการใช้งานของแอปพลิเคชัน

แนวปฏิบัติที่ดีที่สุดสำหรับการเรียงลำดับ Modifier: วางตัวแก้ไขในลำดับที่สมเหตุผล: แรกขนาด/ระยะประกาด (เลเอาต์) จากนั้นการตกแต่ง (background, border) จากนั้นพฤติกรรม (clickable, pointerInput) ทั้งนี้ไม่เพียงช่วยเพิ่มความสามารถในการอ่านแต่ยังช่วยให้ Compose Runtime ประมวลผลสายโซ่ได้ดีขึ้นในระหว่งการวัดค่า หลีกเลี่ยงการใช้ Box ซ้อนกันมากเกินไปด้วย Modifier ที่แตกต่างกัน — บ่อยครั้ง Modifier เดียวบนคอนเทนเนอร์แม่สามารถแทนที่ 2-3 ตัวที่ซ้อนกันได้

kotlin
// ✅ ดี: ค่าคงที่นอก Composable
private val cardModifier = Modifier
    .fillMaxWidth()
    .padding(16.dp)
    .clip(RoundedCornerShape(8.dp))

@Composable
fun CardContent() {
    Box(cardModifier.background(Color.White)) { ... }
}

// ❌ แย่: การสร้างใหม่ในทุกการประกอบใอม่
@Composable
fun BadCard() {
    Box(Modifier.fillMaxWidth().padding(16.dp)) { ... }
}

// ✅ ดี: remember สำหรับ Modifier แบบเปลี่ยนแปลง
@Composable
fun DynamicCard(color: Color) {
    val modifier = remember(color) {
        Modifier.fillMaxWidth().background(color)
    }
    Box(modifier) { ... }
}

คำถามที่พบบ่อย

ฉันสามารถใช้ Modifier เดียวกันสำหรับหลายองค์ประกอบ Composable ได้หรือไม่?

ได้ Modifier เป็นอมมิตแบบไม่สามารถเปลี่ยนแปลงได้ ดังนั้นอ็อบเจกต์ดีวสามารถใช้ได้อย่างปลอดภัยในหลายตำแหน่ง อย่างไรก็ตาม หากคุณใช้ตัวแก้ไขแบบ composed แต่ละการเรียกจะสร้างอินสแตนซ์ใหม่ สำหรับสายโซ่แบบคงที่ ค่าคงที่หรือ val นอก Composable เป็นทางเลือกที่ดีที่สุด

วิธีแก้ไขบักสายโซ่ตัวแก้ไข?

ใช้ Layout Inspector ใน Android Studio — มันจะแสดงขอบเขตของแต่ละ Modifier ในแบบภาพ สำหรับการแก้ไขบักแบบโปรแกรม ให้เพิ่ม Modifier.border() ด้วยสีที่แตกต่างกันในแต่ละขั้นตอนของสายโซ่ เพื่อดูขอบเขตของแต่ละตัวแก้ไข

Modifier.then() คืออะไรแตกต่างจากการเรียกเรียงลำดับอย่างไร?

Modifier.then(other) เชื่อมต่อสายโซ่ other ไปยัง this การเรียกเรียงลำดับ (Modifier.a().b()) เท่ากับ Modifier.then(a()).then(b()) ไม่มีความแตกต่าง — เป็นกลไกสายโซ่เดียวกัน then() มีประโยชน์เมื่อคุณต้องการเชื่อมต่อสายโซ่สำเร็จรูปจากตัวแปร

Modifier ในการแสดงผลความหมายของ Accessibility อย่างไร?

Modifier.semantics {} กำหนดว่าองค์ประกอบจะถูกอธิบายให้กับโปรแกรมอ่านหน้าจออย่างไร Modifier.clickable() จะเพิ่มบทบาทปุ่มและ Action(OnClick) โดยอัตโนมัติ สำหรับท่าทางที่กำหนดเอง คุณต้องระบุอย่างชัดเจน semantics หากไม่มีตัวแก้ไขเชิงความหมาย ผู้ใช้ TalkBack จะไม่สามารถโต้ตอบกับองค์ประกอบที่กำหนดเองได้

ทำไม background ใน Modifier ถึงไม่ทำงานกับมุมกลม?

Modifier.background(color, shape) ทำงานกับมุมได้ แต่ clip() ต้องมาก่อน background เพื่อตัดมุม ลำดับที่ถูกต้อง: clip(shape).background(color) หากคุณต้องการตัดเนื้อหาภายในด้วย ให้ใช้ clipToBounds() บนตัวแม่

สรุป

  • Modifier เป็นอ็อบเจกต์ที่ไม่สามารถเปลี่ยนแปลงได้สำหรับการอธิบายลักษณะและพฤติกรรมแบบแสดงผล
  • ลำดับ ของตัวแก้ไขกำหนดผลลัพธ์: padding → clickable vs clickable → padding
  • สายโซ่ ถูกสร้างเรียงลำดับ แต่ละองค์ประกอบห่อหุ้มตัวก่อนหน้า
  • Modifier.composed ช่วยให้สร้างตัวแก้ไขด้วยสถานะและ CompositionLocal
  • ประสิทธิภาพ: ย้ายสายโซ่คงที่ไปยังค่าคงที่ ใช้ remember สำหรับสายโซ่แบบเปลี่ยนแปลง
  • ความหมาย: Modifier.semantics จำเป็นสำหรับการเข้าถึงขององค์ประกอบที่กำหนดเอง
  • คำแนะนำ: จัดเรียงตัวแก้ไขจากเลเอาต์ไปยังการตกแต่ง แล้วจึงไปยังพฤติกรรม

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม