Column là một thành phần Composable tích hợp của Jetpack Compose từ gói compose.foundation.layout, sắp xếp các phần tử con theo chiều dọc, cái nọ dưới cái kia. Column tương đương với LinearLayout theo hướng dọc từ hệ thống View cũ, nhưng không giống như nó, sử dụng mô tả khai báo và tự động phản ứng với các thay đổi trạng thái. Theo Google Android Developers, 2026, Column là một trong ba container cơ bản cùng với Row và Box.
Những điểm chính
Column là một hàm Composable chấp nhận các tham số tùy chọn: modifier, verticalArrangement, horizontalAlignment và content — một lambda với ColumnScope. Bên trong Column, các hàm Composable con được sắp xếp từ trên xuống dưới theo thứ tự khai báo. Chiều cao của Column bằng tổng chiều cao của các phần tử con cộng với không gian được chỉ định bởi Arrangement. Chiều rộng bằng chiều rộng tối đa của phần tử con có tính đến Alignment.
Column là một container vô hình: nó không có nền hoặc đường viền mặc định. Nếu bạn cần nền, hãy thêm Modifier.background() vào chính Column. Không giống như LazyColumn, Column hiển thị tất cả các phần tử con cùng lúc và không hỗ trợ ảo hóa. Điều này có nghĩa là Column chỉ phù hợp với tập dữ liệu nhỏ — lên đến 10-15 phần tử. Đối với danh sách dài, hãy sử dụng LazyColumn.
ColumnScope là receiver cho lambda content của Column. Nó cung cấp các modifier bổ sung chỉ hoạt động bên trong Column: weight(), align(), alignByBaseline(). Các modifier này không có ý nghĩa bên ngoài Column vì chúng phụ thuộc vào đặc thù của bố cục dọc. Ví dụ: Modifier.align(Alignment.CenterHorizontally) căn chỉnh phần tử con vào giữa Column theo chiều ngang.
VerticalArrangement xác định cách không gian dọc được phân bổ giữa các phần tử. Các giá trị có sẵn: Arrangement.Top (mặc định), Bottom, Center, SpaceBetween, SpaceEvenly, SpaceAround. Nếu chiều cao của Column lớn hơn tổng chiều cao của các phần tử, Arrangement sẽ phân bổ không gian trống. Nếu các phần tử chiếm toàn bộ chiều cao, Arrangement không có tác dụng.
HorizontalAlignment thiết lập căn chỉnh ngang của mỗi phần tử con. Alignment.Start (mặc định cho LTR), CenterHorizontally, End. Alignment tác động lên mỗi phần tử độc lập: nếu một phần tử hẹp và phần tử khác rộng, phần tử đầu tiên sẽ được căn chỉnh, phần tử thứ hai có thể vượt ra ngoài ranh giới Column. Alignment chỉ hoạt động nếu Column có chiều rộng cố định hoặc fillMaxWidth.
Modifier cho Column: Column chấp nhận Modifier được áp dụng cho chính container. Modifier.fillMaxWidth(), fillMaxHeight(), size(), padding() — tất cả các modifier tiêu chuẩn đều hoạt động. Lưu ý đặc biệt: Modifier.height(IntrinsicSize.Min) buộc Column tính toán chiều cao tối thiểu dựa trên các phần tử con bằng cách sử dụng phép đo Intrinsic.
@Composable
fun ColumnArrangementDemo() {
Column(
modifier = Modifier.fillMaxSize().background(Color(0xFFF5F5F5)),
verticalArrangement = Arrangement.SpaceEvenly,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("Trên", modifier = Modifier.background(Color.Cyan))
Text("Giữa", modifier = Modifier.background(Color.Magenta))
Text("Dưới", modifier = Modifier.background(Color.Yellow))
}
}
// IntrinsicSize: Column điều chỉnh chiều cao theo nội dung
@Composable
fun IntrinsicColumn() {
Column(
modifier = Modifier
.height(IntrinsicSize.Min)
.width(200.dp)
) {
Text("Văn bản ngắn")
Text("Một văn bản rất dài sẽ xuống dòng bên trong cột")
}
}
| Arrangement | Hành vi |
|---|---|
| Arrangement.Top | Các phần tử dính lên trên, không gian trống ở dưới |
| Arrangement.Center | Các phần tử ở giữa, không gian chia đều trên và dưới |
| Arrangement.SpaceBetween | Phần tử đầu ở trên, cuối ở dưới, còn lại đều nhau |
| Arrangement.SpaceEvenly | Khoảng cách bằng nhau giữa tất cả phần tử và các cạnh |
| Arrangement.SpaceAround | Khoảng cách bằng nhau giữa các phần tử, nửa khoảng cách ở cạnh |
Modifier.weight() là một modifier ColumnScope phân bổ không gian dọc trống giữa các phần tử Column theo tỷ lệ với trọng số được chỉ định. Nếu Column chiếm 400dp chiều cao và tổng chiều cao của các phần tử con là 100dp, thì 300dp còn lại được chia cho các phần tử có weight. Một phần tử có weight(2f) sẽ nhận được gấp đôi không gian so với phần tử có weight(1f).
fill — tham số thứ hai của weight: weight(weight: Float, fill: Boolean = true). Nếu fill = true (mặc định), phần tử mở rộng ra toàn bộ chiều cao khả dụng. Nếu fill = false, phần tử chỉ chiếm chiều cao nội tại của nó và không gian còn lại trống. Điều này hữu ích khi một phần tử cần được dính vào một bên nhưng weight chỉ xác định tỷ lệ phân bổ không gian trống.
Giới hạn của weight: weight chỉ hoạt động trong Column có chiều cao cố định hoặc fillMaxHeight(). Nếu chiều cao của Column được xác định bởi các phần tử con (wrap content), trọng số không có ý nghĩa — không có không gian trống để phân bổ. Ngoài ra, weight không thể kết hợp với Modifier.height() trên cùng một phần tử — chúng xung đột và weight bị bỏ qua.
@Composable
fun WeightedColumn() {
Column(
modifier = Modifier.fillMaxHeight().width(300.dp)
) {
// Chiếm 1/6 chiều cao (weight 1 của tổng 1+2+3=6)
Box(
modifier = Modifier
.weight(1f)
.fillMaxWidth()
.background(Color.Red)
)
// Chiếm 2/6 chiều cao
Box(
modifier = Modifier
.weight(2f)
.fillMaxWidth()
.background(Color.Green)
)
// Chiếm 3/6 chiều cao
Box(
modifier = Modifier
.weight(3f)
.fillMaxWidth()
.background(Color.Blue)
)
}
}
Column hiển thị tất cả các phần tử con ngay lập tức. Nếu có hơn 10-15 phần tử, Column tạo ra tải trọng đáng kể cho quá trình composition và đo lường. LazyColumn, ngược lại, chỉ hiển thị các phần tử visible và tái sử dụng các phần tử invisible. Đối với danh sách dài, danh sách hàng nghìn phần tử, danh sách vô hạn hoặc trò chuyện — LazyColumn là bắt buộc.
Khi nào Column tốt hơn: màn hình biểu mẫu (3-10 trường), thẻ hồ sơ, cột dọc với biểu tượng, menu. Column cũng hỗ trợ IntrinsicSize, hữu ích cho chiều cao thích ứng. Ngoài ra, Column dễ gỡ lỗi hơn — không có ảo hóa, tất cả các phần tử đều hiển thị trong Layout Inspector. Đối với UI tĩnh, Column là lựa chọn đúng đắn.
LazyColumn cung cấp: bộ nhớ đệm item, định danh dựa trên khóa, hiệu ứng thêm/xóa (animateItemPlacement), tiêu đề cố định (sticky headers). Nếu danh sách chứa các phần tử thuộc các loại khác nhau (viewType khác nhau), hãy sử dụng LazyColumn với sealed class trong items. Column không hỗ trợ sticky headers (chúng cần được mô phỏng qua Column có thể cuộn). Ngoài ra, LazyColumn hỗ trợ LazyVerticalGrid khi sử dụng GridCells.
| Tiêu chí | Column | LazyColumn |
|---|---|---|
| Số lượng phần tử | Lên đến 10-15 | Bất kỳ |
| Hiệu suất | Luôn hiển thị tất cả | Chỉ visible + bộ đệm |
| Cuộn | Qua Modifier.verticalScroll | Tích hợp |
| IntrinsicSize | Hỗ trợ | Không hỗ trợ |
| Tiêu đề cố định | Không (mô phỏng) | Có (stickyHeader) |
| Hiệu ứng phần tử | Không tích hợp | animateItemPlacement |
Hãy xem xét màn hình hồ sơ người dùng nơi Column được sử dụng làm container chính cho avatar, tên, tiểu sử và các nút hành động. Ở đây, Column với IntrinsicSize.Min điều chỉnh theo nội dung và weight được sử dụng để phân bổ không gian giữa các phần.
@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)
) {
// Ảnh đại diện
Icon(
imageVector = Icons.Default.AccountCircle,
contentDescription = "Avatar",
modifier = Modifier.size(64.dp)
)
// Tên
Text(name, style = MaterialTheme.typography.headlineSmall)
// Tiểu sử
Text(bio, style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(top = 4.dp))
// Nút hành động
Row(
horizontalArrangement = Arrangement.spacedBy(12.dp),
modifier = Modifier.padding(top = 12.dp)
) {
Button(onClick = { }) { Text("Tin nhắn") }
OutlinedButton(onClick = { }) { Text("Theo dõi") }
}
}
}
}
Trong ví dụ, Column sử dụng Arrangement.spacedBy(8.dp) để có khoảng cách đều giữa các phần tử. horizontalAlignment = CenterHorizontally căn giữa avatar, tên và tiểu sử. Row bên trong Column là một container lồng nhau cho các nút trên một hàng. Sự kết hợp giữa Column (bố cục dọc) và Row (bố cục ngang) này là một mẫu xây dựng UI điển hình trong Compose.
Câu hỏi thường gặp
Column hiển thị tất cả các phần tử con cùng lúc, điều này gây giảm FPS khi có 100+ phần tử. LazyColumn chỉ hiển thị các phần tử visible cộng với bộ đệm (thường 3-5 màn hình). Đối với màn hình tĩnh với 3-10 phần tử, Column nhanh hơn vì không có chi phí ảo hóa.
Thêm Modifier.verticalScroll(rememberScrollState()) vào Column. Điều này làm cho Column có thể cuộn nhưng không cung cấp ảo hóa — tất cả các phần tử vẫn được hiển thị cùng lúc. Đối với danh sách cuộn dài, hãy sử dụng LazyColumn.
Có, việc lồng Row/Column là thực hành phổ biến. Bằng cách kết hợp hai container, bạn có thể xây dựng các lưới phức tạp. Tuy nhiên, tránh lồng quá sâu (4+ cấp) khi không cần thiết — điều này làm tăng số lần đo LayoutNode và làm chậm quá trình composition.
Sử dụng Modifier.fillMaxWidth() trên mỗi phần tử con. Nếu Column có Modifier.fillMaxWidth(), tất cả các phần tử con với fillMaxWidth() sẽ mở rộng ra toàn bộ chiều rộng. Thay thế: sử dụng Modifier.weight(1f) trong ColumnScope nếu Column nằm trong một container cố định.
Arrangement.spacedBy(space) thêm một khoảng cách cố định giữa mỗi hai phần tử liền kề. Không giống như SpaceBetween/SpaceAround, spacedBy không kéo dãn các phần tử — khoảng cách là cố định và không gian còn lại ở cuối Column. spacedBy không thêm khoảng cách trước phần tử đầu tiên hoặc sau phần tử cuối cùng.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm