Column เป็นคอมโพเนนต์ Composable ในตัวของ Jetpack Compose จากแพ็คเกจ compose.foundation.layout ที่จัดเรียงองค์ประกอบลูกในแนวตั้ง เรียงต่อกันลงมา Column เทียบเท่ากับ LinearLayout ในแนวตั้งจากระบบ View แบบเก่า แต่แตกต่างตรงที่ใช้คำอธิบายแบบประกาศ (declarative) และตอบสนองต่อการเปลี่ยนแปลงสถานะโดยอัตโนมัติ ตาม Google Android Developers, 2026 Column เป็นหนึ่งในสามคอนเทนเนอร์พื้นฐานควบคู่กับ Row และ Box
ประเด็นสำคัญ
Column คือฟังก์ชัน Composable ที่รับพารามิเตอร์แบบเลือกได้: modifier, verticalArrangement, horizontalAlignment และ content — แลมบ์ดาที่มี ColumnScope ภายใน Column ฟังก์ชัน Composable ลูกจะถูกจัดเรียงจากบนลงล่างตามลำดับการประกาศ ความสูงของ Column เท่ากับผลรวมของความสูงขององค์ประกอบลูกบวกกับพื้นที่ที่ระบุโดย Arrangement ความกว้างเท่ากับความกว้างสูงสุดขององค์ประกอบลูกโดยพิจารณาจาก Alignment
Column เป็นคอนเทนเนอร์ที่มองไม่เห็น: ไม่มีพื้นหลังหรือขอบเขตตามค่าเริ่มต้น หากคุณต้องการพื้นหลัง ให้เพิ่ม Modifier.background() ไปที่ Column โดยตรง แตกต่างจาก LazyColumn ตรงที่ Column จะเรนเดอร์องค์ประกอบลูกทั้งหมดพร้อมกันและไม่รองรับการทำเวอร์ช่วลไลเซชัน ซึ่งหมายความว่า Column เหมาะสำหรับชุดข้อมูลขนาดเล็กเท่านั้น — สูงสุด 10-15 องค์ประกอบ สำหรับรายการยาว ให้ใช้ LazyColumn
ColumnScope คือ receiver สำหรับแลมบ์ดา content ของ Column โดยให้มอดิฟายเออร์เพิ่มเติมที่ทำงานเฉพาะภายใน Column: weight(), align(), alignByBaseline() มอดิฟายเออร์เหล่านี้ไม่มีความหมายนอก Column เนื่องจากขึ้นอยู่กับลักษณะเฉพาะของการจัดวางแนวตั้ง ตัวอย่างเช่น Modifier.align(Alignment.CenterHorizontally) จัดแนวองค์ประกอบลูกไปยังกึ่งกลางของ Column ในแนวนอน
VerticalArrangement กำหนดว่าพื้นที่แนวตั้งระหว่างองค์ประกอบจะถูกกระจายอย่างไร ค่าที่มี: Arrangement.Top (ค่าเริ่มต้น), Bottom, Center, SpaceBetween, SpaceEvenly, SpaceAround หากความสูงของ Column มากกว่าผลรวมของความสูงขององค์ประกอบ Arrangement จะกระจายพื้นที่ว่าง หากองค์ประกอบกินพื้นที่ความสูงทั้งหมด Arrangement จะไม่มีผล
HorizontalAlignment กำหนดการจัดแนวแนวนอนของแต่ละองค์ประกอบลูก Alignment.Start (ค่าเริ่มต้นสำหรับ LTR), CenterHorizontally, End Alignment ทำงานกับแต่ละองค์ประกอบอย่างอิสระ: หากองค์ประกอบหนึ่งแคบและอีกองค์ประกอบกว้าง องค์ประกอบแรกจะถูกจัดแนว องค์ประกอบที่สองอาจเลยขอบเขตของ Column Alignment ทำงานเฉพาะเมื่อ Column มีความกว้างคงที่หรือ fillMaxWidth
Modifier สำหรับ Column: Column รับ Modifier ที่ใช้กับคอนเทนเนอร์เอง Modifier.fillMaxWidth(), fillMaxHeight(), size(), padding() — มอดิฟายเออร์มาตรฐานทั้งหมดทำงาน หมายเหตุพิเศษ: Modifier.height(IntrinsicSize.Min) บังคับให้ Column คำนวณความสูงต่ำสุดตามองค์ประกอบลูกโดยใช้การวัด Intrinsic
@Composable
fun ColumnArrangementDemo() {
Column(
modifier = Modifier.fillMaxSize().background(Color(0xFFF5F5F5)),
verticalArrangement = Arrangement.SpaceEvenly,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("บน", modifier = Modifier.background(Color.Cyan))
Text("กลาง", modifier = Modifier.background(Color.Magenta))
Text("ล่าง", modifier = Modifier.background(Color.Yellow))
}
}
// IntrinsicSize: Column ปรับความสูงตามเนื้อหา
@Composable
fun IntrinsicColumn() {
Column(
modifier = Modifier
.height(IntrinsicSize.Min)
.width(200.dp)
) {
Text("ข้อความสั้น")
Text("ข้อความที่ยาวมากซึ่งจะถูกตัดในคอลัมน์")
}
}
| Arrangement | พฤติกรรม |
|---|---|
| Arrangement.Top | องค์ประกอบชิดด้านบน พื้นที่ว่างด้านล่าง |
| Arrangement.Center | องค์ประกอบอยู่กึ่งกลาง พื้นที่แบ่งเท่ากันบนและล่าง |
| Arrangement.SpaceBetween | องค์ประกอบแรกบนสุด สุดท้ายล่างสุด ที่เหลือเท่ากัน |
| Arrangement.SpaceEvenly | ช่องว่างเท่ากันระหว่างองค์ประกอบทั้งหมดและขอบ |
| Arrangement.SpaceAround | ช่องว่างเท่ากันระหว่างองค์ประกอบ ครึ่งหนึ่งที่ขอบ |
Modifier.weight() เป็นมอดิฟายเออร์ ColumnScope ที่กระจายพื้นที่ว่างแนวตั้งระหว่างองค์ประกอบ Column ตามสัดส่วนของน้ำหนักที่ระบุ หาก Column ครอบครองความสูง 400dp และองค์ประกอบลูกทั้งหมด 100dp ส่วนที่เหลือ 300dp จะถูกแบ่งระหว่างองค์ประกอบที่มี weight องค์ประกอบที่มี weight(2f) จะได้รับพื้นที่เป็นสองเท่าขององค์ประกอบที่มี weight(1f)
fill — พารามิเตอร์ที่สองของ weight: weight(weight: Float, fill: Boolean = true) หาก fill = true (ค่าเริ่มต้น) องค์ประกอบจะยืดออกจนเต็มความสูงที่มี หาก fill = false องค์ประกอบจะใช้ความสูงภายในเท่านั้น และพื้นที่ที่เหลือจะว่างเปล่า ซึ่งมีประโยชน์เมื่อองค์ประกอบต้องชิดด้านใดด้านหนึ่ง แต่ weight กำหนดเพียงสัดส่วนการกระจายพื้นที่ว่าง
ข้อจำกัดของ weight: weight ทำงานเฉพาะใน Column ที่มีความสูงคงที่หรือ fillMaxHeight() หากความสูงของ Column ถูกกำหนดโดยองค์ประกอบลูก (wrap content) น้ำหนักจะไม่มีความหมาย — ไม่มีพื้นที่ว่างให้กระจาย นอกจากนี้ ไม่สามารถรวม weight กับ Modifier.height() บนองค์ประกอบเดียวกันได้ — ขัดแย้งกัน และ weight จะถูกละเว้น
@Composable
fun WeightedColumn() {
Column(
modifier = Modifier.fillMaxHeight().width(300.dp)
) {
// กินพื้นที่ 1/6 ของความสูง (weight 1 จากผลรวม 1+2+3=6)
Box(
modifier = Modifier
.weight(1f)
.fillMaxWidth()
.background(Color.Red)
)
// กินพื้นที่ 2/6 ของความสูง
Box(
modifier = Modifier
.weight(2f)
.fillMaxWidth()
.background(Color.Green)
)
// กินพื้นที่ 3/6 ของความสูง
Box(
modifier = Modifier
.weight(3f)
.fillMaxWidth()
.background(Color.Blue)
)
}
}
Column เรนเดอร์องค์ประกอบลูกทั้งหมดทันที หากมีมากกว่า 10-15 องค์ประกอบ Column จะสร้างภาระหนักให้กับการคอมโพสิชันและการวัด LazyColumn ในทางกลับกัน จะเรนเดอร์เฉพาะองค์ประกอบที่มองเห็นและนำองค์ประกอบที่มองไม่เห็นกลับมาใช้ใหม่ สำหรับรายการยาว รายการที่มีองค์ประกอบนับพัน รายการไม่สิ้นสุด หรือแชท — จำเป็นต้องใช้ LazyColumn
เมื่อใด Column ดีกว่า: หน้าจอฟอร์ม (3-10 ฟิลด์), การ์ดโปรไฟล์, คอลัมน์แนวตั้งพร้อมไอคอน, เมนู Column ยังรองรับ IntrinsicSize ซึ่งมีประโยชน์สำหรับความสูงแบบปรับตัวได้ นอกจากนี้ Column ยังดีบักง่ายกว่า — ไม่มีการทำเวอร์ช่วลไลเซชัน องค์ประกอบทั้งหมดมองเห็นได้ใน Layout Inspector สำหรับ UI แบบคงที่ Column เป็นตัวเลือกที่ถูกต้อง
LazyColumn ให้: การแคชไอเท็ม, การระบุตัวตนตามคีย์, แอนิเมชันการเพิ่ม/ลบ (animateItemPlacement), ส่วนหัวแบบติดหนึบ (sticky headers) หากรายการมีองค์ประกอบประเภทต่างกัน (viewType ต่างกัน) ให้ใช้ LazyColumn กับ sealed class ใน items Column ไม่รองรับ sticky headers (ต้องจำลองผ่าน Column ที่เลื่อนได้) นอกจากนี้ LazyColumn ยังรองรับ LazyVerticalGrid เมื่อใช้ GridCells
| เกณฑ์ | Column | LazyColumn |
|---|---|---|
| จำนวนองค์ประกอบ | สูงสุด 10-15 | เท่าใดก็ได้ |
| ประสิทธิภาพ | เรนเดอร์ทั้งหมดเสมอ | เฉพาะที่มองเห็น + บัฟเฟอร์ |
| การเลื่อน | ผ่าน Modifier.verticalScroll | ในตัว |
| IntrinsicSize | รองรับ | ไม่รองรับ |
| ส่วนหัวติดหนึบ | ไม่มี (จำลอง) | มี (stickyHeader) |
| แอนิเมชันองค์ประกอบ | ไม่มีในตัว | animateItemPlacement |
มาดูหน้าจอ โปรไฟล์ผู้ใช้ ที่ใช้ Column เป็นคอนเทนเนอร์หลักสำหรับรูปประจำตัว ชื่อ ประวัติย่อ และปุ่มดำเนินการ ที่นี่ Column ที่มี IntrinsicSize.Min ปรับตามเนื้อหา และ weight ใช้เพื่อกระจายพื้นที่ระหว่างส่วนต่างๆ
@Composable
fun UserProfileCard(name: String, bio: String) {
Card(
modifier = Modifier.fillMaxWidth().padding(16.dp),
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
) {
Column(
modifier = Modifier.fillMaxWidth().padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
// รูปประจำตัว
Icon(
imageVector = Icons.Default.AccountCircle,
contentDescription = "Avatar",
modifier = Modifier.size(64.dp)
)
// ชื่อ
Text(name, style = MaterialTheme.typography.headlineSmall)
// ประวัติย่อ
Text(bio, style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(top = 4.dp))
// ปุ่มดำเนินการ
Row(
horizontalArrangement = Arrangement.spacedBy(12.dp),
modifier = Modifier.padding(top = 12.dp)
) {
Button(onClick = { }) { Text("ข้อความ") }
OutlinedButton(onClick = { }) { Text("ติดตาม") }
}
}
}
}
ในตัวอย่าง Column ใช้ Arrangement.spacedBy(8.dp) เพื่อให้มีระยะห่างเท่ากันระหว่างองค์ประกอบ horizontalAlignment = CenterHorizontally จัดกึ่งกลางรูปประจำตัว ชื่อ และประวัติย่อ Row ภายใน Column เป็นคอนเทนเนอร์ซ้อนสำหรับปุ่มในหนึ่งแถว การรวมกันของ Column (การจัดวางแนวตั้ง) และ Row (การจัดวางแนวนอน) เป็นรูปแบบการสร้าง UI ทั่วไปใน Compose
คำถามที่พบบ่อย
Column เรนเดอร์องค์ประกอบลูกทั้งหมดพร้อมกัน ซึ่งทำให้ FPS ลดลงเมื่อมี 100+ องค์ประกอบ LazyColumn เรนเดอร์เฉพาะองค์ประกอบที่มองเห็นและบัฟเฟอร์ (ปกติ 3-5 หน้าจอ) สำหรับหน้าจอคงที่ที่มี 3-10 องค์ประกอบ Column จะเร็วกว่าเนื่องจากไม่มีโอเวอร์เฮดของการทำเวอร์ช่วลไลเซชัน
เพิ่ม Modifier.verticalScroll(rememberScrollState()) ไปที่ Column ทำให้ Column เลื่อนได้แต่ไม่มีการทำเวอร์ช่วลไลเซชัน — องค์ประกอบทั้งหมดยังคงเรนเดอร์พร้อมกัน สำหรับรายการยาวที่เลื่อนได้ ให้ใช้ LazyColumn
ได้ การซ้อน Row/Column เป็นแนวทางปฏิบัติทั่วไป การรวมสองคอนเทนเนอร์เข้าด้วยกันทำให้คุณสร้างกริดที่ซับซ้อนได้ อย่างไรก็ตาม หลีกเลี่ยงการซ้อนลึก (4+ ระดับ) โดยไม่จำเป็น — จะเพิ่มจำนวนการวัด LayoutNode และทำให้การคอมโพสิชันช้าลง
ใช้ Modifier.fillMaxWidth() บนแต่ละองค์ประกอบลูก หาก Column มี Modifier.fillMaxWidth() องค์ประกอบลูกทั้งหมดที่มี fillMaxWidth() จะยืดออกเต็มความกว้าง ทางเลือก: ใช้ Modifier.weight(1f) ใน ColumnScope หาก Column อยู่ในคอนเทนเนอร์คงที่
Arrangement.spacedBy(space) เพิ่มระยะห่างคงที่ระหว่างทุกสององค์ประกอบที่ติดกัน แตกต่างจาก SpaceBetween/SpaceAround ตรงที่ spacedBy ไม่ยืดองค์ประกอบ — ระยะห่างคงที่ และพื้นที่ที่เหลือจะอยู่ที่ส่วนท้ายของ Column spacedBy ไม่เพิ่มระยะห่างก่อนองค์ประกอบแรกหรือหลังองค์ประกอบสุดท้าย
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม