Composable Function เป็นหน่วยพื้นฐานของส่วนติดต่อผู้ใช้ใน Jetpack Compose ที่กำหนดว่าส่วนหนึ่งของหน้าจอควรมีลักษณะและประพฤติกรรมอย่างไร แต่ละฟังก์ชันดังกล่าวจะถูกทำเครื่องหมายด้วย @Composable annotation และทำงานในบริบทพิเศษที่ทำให้ Compose สามารถติดตามการพึ่งพาและสร้าง UI ใหม่โดยอัตโนมัติเมื่อข้อมูลเปลี่ยนแปลง ตาม Google Android Developers, 2026 การสร้างฟังก์ชัน Composable ที่ถูกต้องมีผลโดยตรงต่อประสิทธิภาพของแอปพลิเคชันและประสิทธิภาพของการประกอบใหม่
ประเด็นสำคัญ
Composable Function คือฟังก์ชันในภาษา Kotlin ที่มี @Composable annotation ซึ่งอธิบายส่วนหนึ่งของส่วนติดต่อผู้ใช้โดยการประกาศแบบดีเคลอร์เทิฟ แทนที่จะสร้างและกำหนดค่าวัตถุ View ผ่านโค้ด Java หรือ XML markup นักพัฒนาเพียงเขียนว่า UI ควรมีลักษณะอย่างไรสำหรับแต่ละสถานะของข้อมูล
ความแตกต่างหลักระหว่างฟังก์ชัน Composable และระบบ View แบบดั้งเดิมของ Android อยู่ที่โมเดลการอัพเดท ในแนวทางเดิม นักพัฒนาจะเรียก findViewById ด้วยตนเอง เปลี่ยนข้อความผ่าน setText และจัดการมองเห็นผ่าน setVisibility Composable Function ช่วยให้คุณหลุดพ้นการทำซ้ำเหล่านี้
คอมไพเลอร์ Kotlin เมื่อประมวลผล @Composable annotation จะสร้างโค้ดเพิ่มเติมที่รวมฟังก์ชันเข้ากับกลไกการประกอบ โค้ดนี้รวมถึงการอ่านและเขียนใน slots — เซลล์หน่วยความจำที่เก็บสถานะและพารามิเตอร์ของแต่ละฟังก์ชัน Composable ในต้นไม้ UI ปัจจุบัน
ไวยากรณ์ของ ฟังก์ชัน Composable กระชับและรวดเร็ว: เพียงเพิ่ม @Composable ก่อนคำสำคัญ fun ฟังก์ชันสามารถรับพารามิเตอร์ใดๆ รวมถึงการเรียก Composable อื่นในตัวและใช้โครงสร้าง Kotlin — เงื่อนไข ลูป นิพจน์ when — สำหรับการแสดงผล UI แบบมีเงื่อนไข
@Composable
fun ProductItem(
product: Product,
modifier: Modifier = Modifier,
onAddToCart: () -> Unit
) {
Card(modifier = modifier.padding(8.dp)) {
Row(modifier = Modifier.fillMaxWidth().padding(12.dp),
verticalAlignment = Alignment.CenterVertically) {
Column(modifier = Modifier.weight(1f)) {
Text(text = product.name, style = MaterialTheme.typography.titleMedium)
Text(text = "${product.price}", color = MaterialTheme.colorScheme.primary)
}
Button(onClick = onAddToCart) {
Text("เพิ่มในตะกร้า")
}
}
}
}
ในตัวอย่างนี้ ฟังก์ชัน Composable ProductItem รับอ็อบเจกต์ Product ตัวแก้ไขและ callback พารามิเตอร์ทั้งสามไม่สามารถเปลี่ยนแปลงได้ ซึ่งรับประกันพฤติกรรมที่คาดเดาได้ระหว่างการประกอบใหม่ ตัวแก้ไขจะถูกส่งเป็นพารามิเตอร์ที่มีค่าเรียกเรียงแบบเริ่มต้น
ภายใน ฟังก์ชัน Composable จะใช้ส่วนประกอบ Material Design ในตัว (Text, Button, Card, TextField) หรือประเภทพื้นฐาน (Canvas, Layout) แต่ละส่วนประกอบรับพารามิเตอร์สำหรับการกำหนดค่าลักษณะและพฤติกรรม รวมถึงตัวแก้ไขหนึ่งหรือมากกว่าผ่านพารามิเตอร์ modifier
ตัวแก้ไขคือโซ่ของฟังก์ชันที่เปลี่ยนขนาด ตำแหน่ง การจัดการกับอิวเวนต์และลักษณะของส่วนประกอบ ลำดับ ของตัวแก้ไขในโซ่มีความสำคัญ: clickable.semantics ทำงานต่างจาก semantics.clickable และ padding.background ทาสีทั้งพื้นที่และพื้นหลังรวมถึง padding
ภายในฟังก์ชัน Composable คุณสามารถใช้เงื่อนไข if และ when สำหรับการแสดงผลแบบมีเงื่อนไขของส่วนต่างๆ ของ UI รวมถึงการใช้ลูป for สำหรับรายการแบบไฮน์ โครงสร้างทั้งหมดทำงานได้อย่างเป็นธรรมชาติเพราะ Kotlin เป็นภาษาโปรแกรมที่สมบูรณ์และอย่างไรก็ตาม หากเงื่อนไขหรือลูปมีการเรียกฟังก์ชัน Composable มันก็จะมีส่วนร่วมในการประกอบใหม่
@Composable
fun ProductList(
products: List<Product>,
modifier: Modifier = Modifier
) {
LazyColumn(modifier = modifier) {
items(products, key = { it.id }) { product ->
ProductItem(
product = product,
onAddToCart = { /* add to cart */ }
)
}
}
}
ลองพิจารณาตัวอย่างหน้าจอค้นหาสินค้าที่ใช้หลาย ฟังก์ชัน Composable รูปแบบทั่วไปจะแสดงในที่นี่: ช่องกรอกข้อมูลที่มีสถานะ การกรองรายการ การจัดการผลลัพธ์ว่างและการโหลด
data class Product(
val id: String,
val name: String,
val price: Double,
val category: String
)
@Composable
fun SearchScreen() {
var query by remember { mutableStateOf("") }
val products = remember(query) { getFilteredProducts(query) }
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
OutlinedTextField(
value = query,
onValueChange = { query = it },
label = { Text("ค้นหาสินค้า") },
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
when (products) {
is Loading -> CircularProgressIndicator()
is Empty -> Text("ไม่พบผลลัพธ์")
is Result -> LazyColumn {
items(products.items, key = { it.id }) { product ->
ProductItem(product = product, onAddToCart = {})
}
}
}
}
}
ตัวอย่างนี้แสดงรูปแบบหลายอย่างพร้อมกัน: remember สำหรับการรักษาสถานะคำค้นหา remember(query) สำหรับการกรองด้วยคีย์ when สำหรับสามสถานะ UI และ LazyColumn สำหรับการแสดงรายการที่มีประสิทธิภาพ
ฟังก์ชัน Composable รับพารามิเตอร์เหมือนฟังก์ชัน Kotlin ทั่วไป แต่มีข้อแตกต่างที่สำคัญ: พารามิเตอร์สามารถเป็นฟังก์ชัน Composable อื่นที่ส่งผ่าน lambda ด้วย @Composable annotation กลไกนี้เรียกว่า Slot API และเป็นรูปแบบหลักสำหรับการสร้างคอนเทนเนอร์ที่สามารถใช้ซ้ำได้
Slot API แก้ไขปัญหาที่ในระบบ View แบบดั้งเดิมแก้ไขโดย ViewGroup และการเพิ่ม View ย่อยโดยทางโปรแกรม แทนที่จะใช้เมธอด addView Compose ใช้ content lambda — พารามิเตอร์สุดท้ายที่มีชนิด @Composable () -> Unit
พารามิเตอร์ของฟังก์ชัน Composable สามารถมีค่าเริ่มต้น ซึ่งทำให้การใช้งานในบริบทต่างๆ ง่ายขึ้น แนะนำ ให้ทำเฉพาะพารามิเตอร์ที่จำเป็นต่อการทำงานของฟังก์ชันเท่านั้น
| พารามิเตอร์ | ชนิด | ตัวอย่าง |
|---|---|---|
| จำเป็น | ชนิดใดก็ได้ | name: String |
| เลือกได้ | มีค่าเริ่มต้น | modifier: Modifier = Modifier |
| Content | @Composable () -> Unit | content: @Composable () -> Unit |
| Callback | Lambda ไม่มี @Composable | onClick: () -> Unit |
ในชุมชน Compose มีรูปแบบที่ถูกกำหนดขึ้นหลายอย่างที่ทำให้ ฟังก์ชัน Composable อ่านง่ายและคาดเดาได้มากขึ้น แรกคือ State Hoisting: สถานะจะถูกยกขึ้นไปยังระดับที่สูงขึ้น และฟังก์ชัน Composable จะรับมันผ่านพารามิเตอร์ ทำให้ฟังก์ชันเป็น pure และสามารถใช้ซ้ำในบริบทต่างๆ ได้
รูปแบบที่สองคือพารามิเตอร์ Event-driven แทนที่จะส่ง ViewModel หรือ useCase ไปยังฟังก์ชัน Composable จะส่งเฉพาะ callback ที่เฉพาะเจาะจง: onSave, onDelete, onNavigateToDetail
รูปแบบที่สามคือ CompositionLocal สำหรับการส่งข้อมูลที่ใช้ร่วมกันผ่านต้นไม้การประกอบ โครงการ ความหนาแน่นหน้าจอ เส้นทางปัจจุบัน — ทั้งหมดนี้ถูกส่งผ่าน CompositionLocal หลีกเส้นโส้พารามิเตอร์ผ่านฟังก์ชัน Composable หลายสิบตัว
// State Hoisting: สถานะถูกยกไปยังฟังก์ชันแม่
@Composable
fun CounterDisplay(
count: Int,
onIncrement: () -> Unit
) {
Column(horizontalAlignment = Alignment.CenterHorizontally) {
Text(text = "ตัวนับ: $count", style = MaterialTheme.typography.headlineLarge)
Button(onClick = onIncrement) {
Text("+1")
}
}
}
// การใช้งานกับ State Hoisting
@Composable
fun CounterScreen() {
var count by remember { mutableStateOf(0) }
CounterDisplay(
count = count,
onIncrement = { count++ }
)
}
คำถามที่พบบ่อย
ได้ return ไม่ได้ถูกห้าม แต่ต้องระมัดระวัง Compose ปรับหามการประกอบใหม่ในระดับฟังก์ชันแต่ละตัว และ return ก่อนกำหนดอาจทำลายการปรับหามนี้ ควรใช้ตัวดำเนินงานแบบมีเงื่อนไข if หรือ when ภายในตัวฟังก์ชัน
ใน Kotlin Unit คืออ็อบเจกต์ singleton ไม่ใช่ชนิดว่างเปล่า ฟังก์ชัน Composable คืน Unit ซึ่งทางเทคนิคหมายความว่าพวกมันคืนอ็อบเจกต์ Unit เอง
การส่ง คอลเล็กชันที่เปลี่ยนแปลงได้ ทำได้ แต่เป็นแนวปฏิบัติที่ไม่ดี หากคอลเล็กชันเปลี่ยนแปลง Compose จะไม่รู้เรื่องนั้นเพราะการอ้างอิงของอ็อบเจกต์ยังเหมือนเดิม
สำหรับการดีบัก ใช้ Android Studio กับ Layout Inspector ซึ่งแสดงต้นไม้ฟังก์ชัน Composable ปัจจุบัน ค่าพารามิเตอร์ และสาเหตุของการประกอบใหม่
ฟังก์ชัน Composable จะคืน Unit เสมอ ดังนั้นจึงไม่ต้องระบุชนิดค่าที่ส่งคืน การพยายามคืนชนิดอื่นจะทำให้เกิดข้อผิดพลาดการคอมไพล์
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม