Column: sắp xếp dọc và cấu hình container trong Compose

Tác giả: IT Sectr Đã đăng: 2026-06-28 Thời gian đọc: 8 phút

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 sắp xếp các phần tử theo chiều dọc với cấu hình Arrangement và Alignment
  • Arrangement xác định sự phân bổ không gian giữa các phần tử theo chiều dọc
  • Alignment thiết lập căn chỉnh ngang của mỗi phần tử bên trong Column
  • Weight phân bổ không gian trống theo tỷ lệ giữa các phần tử
  • IntrinsicSize cho phép Column điều chỉnh kích thước theo chiều rộng tối thiểu/tối đa của phần tử con

Column trong Jetpack Compose là gì

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.

Tham số của Column: Arrangement, Alignment, Modifier

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.

kotlin
@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")
    }
}
ArrangementHành vi
Arrangement.TopCác phần tử dính lên trên, không gian trống ở dưới
Arrangement.CenterCác phần tử ở giữa, không gian chia đều trên và dưới
Arrangement.SpaceBetweenPhần tử đầu ở trên, cuối ở dưới, còn lại đều nhau
Arrangement.SpaceEvenlyKhoảng cách bằng nhau giữa tất cả phần tử và các cạnh
Arrangement.SpaceAroundKhoảng cách bằng nhau giữa các phần tử, nửa khoảng cách ở cạnh

Column weight: phân bổ không gian giữa các phần tử

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.

kotlin
@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 vs LazyColumn: khi nào sử dụng loại nào

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íColumnLazyColumn
Số lượng phần tửLên đến 10-15Bất kỳ
Hiệu suấtLuôn hiển thị tất cảChỉ visible + bộ đệm
CuộnQua Modifier.verticalScrollTích hợp
IntrinsicSizeHỗ trợKhông hỗ trợ
Tiêu đề cố địnhKhông (mô phỏng)Có (stickyHeader)
Hiệu ứng phần tửKhông tích hợpanimateItemPlacement

Ví dụ thực tế về sử dụng Column

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.

kotlin
@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 khác LazyColumn như thế nào về hiệu suất?

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.

Làm thế nào để làm cho Column có thể cuộn được?

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ó thể lồng Row bên trong Column và Column bên trong Row không?

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.

Làm thế nào để tất cả các phần tử trong Column có cùng chiều rộng?

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.

spacedBy hoạt động như thế nào trong Column?

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

  • Column — container dọc cơ bản của Compose để sắp xếp các phần tử từ trên xuống dưới
  • Arrangement kiểm soát phân bổ không gian (Top, Center, SpaceBetween, spacedBy)
  • Alignment thiết lập căn chỉnh ngang của mỗi phần tử con
  • Weight phân bổ không gian trống theo tỷ lệ giữa các phần tử
  • Column vs LazyColumn: Column cho 3-10 phần tử, LazyColumn cho danh sách dài
  • IntrinsicSize cho phép Column điều chỉnh chiều cao theo phép đo tối thiểu của phần tử con
  • Khuyến nghị: sử dụng spacedBy cho khoảng cách giữa các phần tử thay vì padding trên mỗi phần 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.

Thảo luận dự án

Đọc thêm