FlowRow
và FlowColumn
là các thành phần kết hợp tương tự như Row
và Column
, nhưng khác ở các mục đó
chuyển sang dòng tiếp theo khi vùng chứa hết không gian. Việc này tạo
nhiều hàng hoặc cột. Bạn cũng có thể kiểm soát số lượng mục trong một dòng bằng cách đặt maxItemsInEachRow
hoặc maxItemsInEachColumn
. Bạn thường có thể sử dụng
FlowRow
và FlowColumn
để tạo bố cục thích ứng – nội dung sẽ không bị cắt
nếu các mục quá lớn cho một kích thước và sử dụng kết hợp
maxItemsInEach*
với Modifier.weight(weight)
có thể giúp tạo bố cục
lấp đầy/mở rộng chiều rộng của hàng hoặc cột khi cần.
Ví dụ điển hình là cho một khối hoặc giao diện người dùng lọc:

FlowRow
Cách sử dụng cơ bản
Để sử dụng FlowRow
hoặc FlowColumn
, hãy tạo các thành phần kết hợp này và đặt các mục
bên trong lớp đó phải tuân theo luồng tiêu chuẩn:
@Composable private fun FlowRowSimpleUsageExample() { FlowRow(modifier = Modifier.padding(8.dp)) { ChipItem("Price: High to Low") ChipItem("Avg rating: 4+") ChipItem("Free breakfast") ChipItem("Free cancellation") ChipItem("£50 pn") } }
Đoạn mã này dẫn đến giao diện người dùng như trên, với các mục tự động chuyển đến hàng tiếp theo khi không còn chỗ trong hàng đầu tiên.
Các tính năng của bố cục luồng
Bố cục flow có các tính năng và thuộc tính mà bạn có thể sử dụng để tạo nhiều bố cục khác nhau trong ứng dụng của mình.
Cách sắp xếp trục chính: sắp xếp theo chiều ngang hoặc chiều dọc
Trục chính là trục mà các mục được bố trí (ví dụ: trong
FlowRow
, các mục được sắp xếp theo chiều ngang). horizontalArrangement
trong FlowRow
kiểm soát cách phân phối dung lượng trống giữa các mục.
Bảng sau đây trình bày ví dụ về cách thiết lập horizontalArrangement
cho các mục
cho FlowRow
:
Sắp xếp theo chiều ngang được đặt trên |
Kết quả |
|
![]() |
![]() |
|
![]() |
|
![]() |
|
![]() |
|
![]() |
Đối với FlowColumn
, bạn có thể sử dụng các tuỳ chọn tương tự với verticalArrangement
, với tuỳ chọn mặc định là Arrangement.Top
.
Sắp xếp theo trục chéo
Trục chéo là trục theo hướng đối diện với trục chính. Để
ví dụ: trong FlowRow
, đây là trục tung. Để thay đổi cách sắp xếp nội dung tổng thể bên trong vùng chứa theo trục chéo, hãy sử dụng verticalArrangement
cho FlowRow
và horizontalArrangement
cho FlowColumn
.
Đối với FlowRow
, bảng sau đây trình bày ví dụ về cách thiết lập các chế độ cài đặt khác nhau
verticalArrangement
cho các mặt hàng:
Đã đặt chế độ sắp xếp theo chiều dọc trên |
Kết quả |
|
![]() |
![]() |
|
![]() |
Đối với FlowColumn
, bạn có thể sử dụng các lựa chọn tương tự cho horizontalArrangement
.
Cách sắp xếp trục chéo mặc định là Arrangement.Start
.
Căn chỉnh từng mục riêng lẻ
Bạn có thể muốn đặt các mục riêng lẻ trong hàng bằng các vị trí khác nhau
căn chỉnh. Điều này khác với verticalArrangement
và
horizontalArrangement
để căn chỉnh các mục trong dòng hiện tại. Bạn có thể áp dụng điều này bằng Modifier.align()
.
Ví dụ: khi các mục trong FlowRow
có chiều cao khác nhau, hàng này sẽ lấy giá trị
chiều cao của mục lớn nhất và áp dụng Modifier.align(alignmentOption)
cho
mục:
Căn chỉnh dọc được đặt trên |
Kết quả |
|
![]() |
![]() |
|
![]() |
Đối với FlowColumn
, bạn có thể sử dụng các lựa chọn tương tự. Căn chỉnh mặc định là Alignment.Start
.
Số mục tối đa trong hàng hoặc cột
Tham số maxItemsInEachRow
hoặc maxItemsInEachColumn
xác định giá trị tối đa
các mục trong trục chính để cho phép trong một dòng trước khi xuống dòng tiếp theo. Chiến lược phát hành đĩa đơn
mặc định là Int.MAX_INT
, cho phép nhiều mục nhất có thể, miễn là
kích thước của chúng cho vừa với đường kẻ.
Ví dụ: việc đặt maxItemsInEachRow
buộc bố cục ban đầu chỉ có 3 mục:
Chưa đặt giới hạn tối đa |
|
![]() |
![]() |
Các mục trong quy trình tải từng phần
ContextualFlowRow
và ContextualFlowColumn
là sự kiện chuyên biệt
phiên bản FlowRow
và FlowColumn
cho phép bạn tải từng phần nội dung
của hàng hoặc cột luồng. Các thuộc tính này cũng cung cấp thông tin về vị trí của mục (chỉ mục, số hàng và kích thước có sẵn), chẳng hạn như liệu mục có nằm trong hàng đầu tiên hay không. Điều này rất hữu ích cho các tập dữ liệu lớn và nếu bạn cần thông tin theo ngữ cảnh về một mục.
Tham số maxLines
giới hạn số hàng hiển thị và tham số overflow
chỉ định nội dung sẽ hiển thị khi đạt đến số lượng mục tràn, cho phép bạn chỉ định expandIndicator
hoặc collapseIndicator
tuỳ chỉnh.
Ví dụ: để hiển thị "+ (số mục còn lại)" hoặc "Ẩn bớt" nút:
val totalCount = 40 var maxLines by remember { mutableStateOf(2) } val moreOrCollapseIndicator = @Composable { scope: ContextualFlowRowOverflowScope -> val remainingItems = totalCount - scope.shownItemCount ChipItem(if (remainingItems == 0) "Less" else "+$remainingItems", onClick = { if (remainingItems == 0) { maxLines = 2 } else { maxLines += 5 } }) } ContextualFlowRow( modifier = Modifier .safeDrawingPadding() .fillMaxWidth(1f) .padding(16.dp) .wrapContentHeight(align = Alignment.Top) .verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(4.dp), horizontalArrangement = Arrangement.spacedBy(8.dp), maxLines = maxLines, overflow = ContextualFlowRowOverflow.expandOrCollapseIndicator( minRowsToShowCollapse = 4, expandIndicator = moreOrCollapseIndicator, collapseIndicator = moreOrCollapseIndicator ), itemCount = totalCount ) { index -> ChipItem("Item $index") }

ContextualFlowRow
Trọng lượng mặt hàng
Trọng số sẽ tăng trọng số của một mục dựa trên hệ số của mục đó và không gian có sẵn trên dòng mục đó
đã được đặt ở đâu. Quan trọng là có sự khác biệt giữa FlowRow
và Row
về cách sử dụng trọng số để tính chiều rộng của một mục. Đối với Rows
, trọng số
dựa trên tất cả các mục trong Row
. Với FlowRow
, trọng số được dựa trên
mục trong dòng mà một mục được đặt vào, không phải tất cả các mục trong
Vùng chứa FlowRow
.
Ví dụ: nếu bạn có 4 mục đều nằm trên một dòng, mỗi mục có trọng số khác nhau là 1f, 2f, 1f
và 3f
, thì tổng trọng số là 7f
. Dung lượng còn lại
trong một hàng hoặc cột sẽ được chia cho 7f
. Sau đó, chiều rộng của mỗi mục sẽ được tính bằng: weight * (remainingSpace / totalWeight)
.
Bạn có thể sử dụng kết hợp Modifier.weight
và tối đa các mục có FlowRow
hoặc
FlowColumn
để tạo bố cục dạng lưới. Phương pháp này hữu ích cho việc tạo bố cục thích ứng điều chỉnh theo kích thước của thiết bị.
Có một vài ví dụ về những gì bạn có thể đạt được bằng cách sử dụng trọng số. Một ví dụ là lưới trong đó các mục có kích thước bằng nhau, như minh hoạ dưới đây:

FlowRow
để tạo lướiĐể tạo lưới có kích thước mục bằng nhau, bạn có thể làm như sau:
val rows = 3 val columns = 3 FlowRow( modifier = Modifier.padding(4.dp), horizontalArrangement = Arrangement.spacedBy(4.dp), maxItemsInEachRow = rows ) { val itemModifier = Modifier .padding(4.dp) .height(80.dp) .weight(1f) .clip(RoundedCornerShape(8.dp)) .background(MaterialColors.Blue200) repeat(rows * columns) { Spacer(modifier = itemModifier) } }
Quan trọng là nếu bạn thêm một mục khác và lặp lại 10 lần thay vì 9 lần,
mục cuối cùng chiếm toàn bộ cột cuối cùng, làm tổng trọng số của toàn bộ hàng
là 1f
:

FlowRow
để tạo lưới có mục cuối cùng chiếm toàn bộ chiều rộngBạn có thể kết hợp trọng số với Modifiers
khác, chẳng hạn như
Modifier.width(exactDpAmount), Modifier.aspectRatio(aspectRatio)
hoặc
Modifier.fillMaxWidth(fraction)
. Tất cả các đối tượng sửa đổi này đều hoạt động cùng nhau để cho phép định cỡ thích ứng các mục trong FlowRow
(hoặc FlowColumn
).
Bạn cũng có thể tạo một lưới xen kẽ gồm các kích thước mục khác nhau, trong đó có hai mục chiếm một nửa chiều rộng của từng mục và một mục chiếm toàn bộ chiều rộng của mục tiếp theo cột:

FlowRow
với kích thước xen kẽ của các hàngBạn có thể thực hiện điều này bằng mã sau:
FlowRow( modifier = Modifier.padding(4.dp), horizontalArrangement = Arrangement.spacedBy(4.dp), maxItemsInEachRow = 2 ) { val itemModifier = Modifier .padding(4.dp) .height(80.dp) .clip(RoundedCornerShape(8.dp)) .background(Color.Blue) repeat(6) { item -> // if the item is the third item, don't use weight modifier, but rather fillMaxWidth if ((item + 1) % 3 == 0) { Spacer(modifier = itemModifier.fillMaxWidth()) } else { Spacer(modifier = itemModifier.weight(0.5f)) } } }
Định cỡ phân số
Bằng cách sử dụng Modifier.fillMaxWidth(fraction)
, bạn có thể chỉ định kích thước của phần tử
vùng chứa mà một mục sẽ chiếm dụng. Điều này khác với cách hoạt động của Modifier.fillMaxWidth(fraction)
khi áp dụng cho Row
hoặc Column
, trong đó các mục Row/Column
chiếm tỷ lệ phần trăm chiều rộng còn lại, thay vì chiều rộng của toàn bộ vùng chứa.
Ví dụ: mã sau đây sẽ tạo ra kết quả khác nhau khi sử dụng FlowRow
so với Row
:
FlowRow( modifier = Modifier.padding(4.dp), horizontalArrangement = Arrangement.spacedBy(4.dp), maxItemsInEachRow = 3 ) { val itemModifier = Modifier .clip(RoundedCornerShape(8.dp)) Box( modifier = itemModifier .height(200.dp) .width(60.dp) .background(Color.Red) ) Box( modifier = itemModifier .height(200.dp) .fillMaxWidth(0.7f) .background(Color.Blue) ) Box( modifier = itemModifier .height(200.dp) .weight(1f) .background(Color.Magenta) ) }
|
![]() |
|
![]() |
fillMaxColumnWidth()
và fillMaxRowHeight()
Áp dụng Modifier.fillMaxColumnWidth()
hoặc
Modifier.fillMaxRowHeight()
với một mục bên trong FlowColumn
hoặc FlowRow
đảm bảo rằng các mục trong cùng một cột hoặc hàng có cùng chiều rộng hoặc chiều cao với
mục lớn nhất trong cột/hàng.
Ví dụ: ví dụ này sử dụng FlowColumn
để hiển thị danh sách các món tráng miệng Android. Bạn có thể thấy sự khác biệt về chiều rộng của từng mục khi
Modifier.fillMaxColumnWidth()
được áp dụng cho các mục so với khi không áp dụng và
các mục xuống dòng.
FlowColumn( Modifier .padding(20.dp) .fillMaxHeight() .fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(8.dp), verticalArrangement = Arrangement.spacedBy(8.dp), maxItemsInEachColumn = 5, ) { repeat(listDesserts.size) { Box( Modifier .fillMaxColumnWidth() .border(1.dp, Color.DarkGray, RoundedCornerShape(8.dp)) .padding(8.dp) ) { Text( text = listDesserts[it], fontSize = 18.sp, modifier = Modifier.padding(3.dp) ) } } }
|
![]() |
Không đặt thay đổi về chiều rộng (các mục gói) |
![]() |
Đề xuất cho bạn
- Lưu ý: văn bản có đường liên kết sẽ hiện khi JavaScript tắt
- Kiến thức cơ bản về bố cục Compose
- ConstraintLayout trong Compose
- Thao tác trong trình chỉnh sửa {:#editor-actions}