FlowRow
и FlowColumn
— это составные элементы, похожие на Row
и Column
, но отличающиеся тем, что элементы переходят на следующую строку, когда в контейнере заканчивается место. Это создает несколько строк или столбцов. Количеством элементов в строке также можно управлять, установив maxItemsInEachRow
или maxItemsInEachColumn
. Вы часто можете использовать FlowRow
и FlowColumn
для создания адаптивных макетов — контент не будет обрезан, если элементы слишком велики для одного измерения, а использование комбинации maxItemsInEach*
с Modifier.weight(weight)
может помочь создать макеты, которые заполняют/расширяют ширину строки или столбца, когда это необходимо.
Типичный пример — чип или фильтрующий пользовательский интерфейс:
Основное использование
Чтобы использовать FlowRow
или FlowColumn
, создайте эти составные элементы и поместите внутри них элементы, которые должны следовать стандартному потоку:
@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") } }
Этот фрагмент приводит к показанному выше пользовательскому интерфейсу, в котором элементы автоматически переходят на следующую строку, когда в первой строке больше нет места.
Особенности проточной компоновки
Макеты потока имеют следующие функции и свойства, которые можно использовать для создания различных макетов в вашем приложении.
Расположение главной оси: горизонтальное или вертикальное расположение
Основная ось — это ось, на которой располагаются элементы (например, в FlowRow
элементы располагаются горизонтально). Параметр horizontalArrangement
в FlowRow
управляет способом распределения свободного пространства между элементами.
В следующей таблице показаны примеры установки horizontalArrangement
для элементов FlowRow
:
Горизонтальное расположение установлено на | Результат |
| |
Для FlowColumn
аналогичные параметры доступны verticalArrangement
со значением по умолчанию Arrangement.Top
.
Расположение поперечной оси
Поперечная ось — это ось, расположенная в направлении, противоположном главной оси. Например, в FlowRow
это вертикальная ось. horizontalArrangement
изменить расположение всего содержимого внутри контейнера по поперечной оси, используйтеverterArrangement для FlowRow
и verticalArrangement
для FlowColumn
.
Для FlowRow
в следующей таблице показаны примеры установки различных verticalArrangement
для элементов:
Вертикальное расположение установлено на | Результат |
| |
Для FlowColumn
аналогичные параметры доступны с horizontalArrangement
. Расположение поперечной оси по умолчанию — Arrangement.Start
.
Выравнивание отдельных элементов
Возможно, вам захочется расположить отдельные элементы внутри строки с разным выравниванием. Это отличается verticalArrangement
и horizontalArrangement
, поскольку оно выравнивает элементы внутри текущей строки . Вы можете применить это с помощью Modifier.align()
.
Например, если элементы в FlowRow
имеют разную высоту, строка принимает высоту самого большого элемента и применяет Modifier.align(alignmentOption)
к элементам:
Вертикальное выравнивание установлено на | Результат |
| |
Для FlowColumn
доступны аналогичные параметры. Выравнивание по умолчанию — Alignment.Start
.
Максимальное количество элементов в строке или столбце
Параметры maxItemsInEachRow
или maxItemsInEachColumn
определяют максимальное количество элементов на главной оси, которое можно разместить в одной строке перед переносом на следующую. По умолчанию используется Int.MAX_INT
, что позволяет использовать как можно больше элементов, если их размеры позволяют им уместиться в строке.
Например, установка maxItemsInEachRow
приводит к тому, что исходный макет будет содержать только 3 элемента:
Нет максимального набора | |
Ленивая загрузка элементов потока
ContextualFlowRow
и ContextualFlowColumn
— это специализированные версии FlowRow
и FlowColumn
, которые позволяют отложенно загружать содержимое строки или столбца потока. Они также предоставляют информацию о положении элемента (индекс, номер строки и доступный размер), например, находится ли элемент в первой строке. Это полезно для больших наборов данных и если вам нужна контекстная информация об элементе.
Параметр maxLines
ограничивает количество отображаемых строк, а параметр overflow
указывает, что должно отображаться при достижении переполнения элементов, что позволяет указать пользовательский expandIndicator
или collapseIndicator
.
Например, чтобы отобразить кнопку «+ (оставшееся количество элементов)» или «Показать меньше»:
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") }
Вес товара
Вес увеличивает элемент в зависимости от его коэффициента и доступного места в строке, в которой он был помещен. Важно отметить, что между FlowRow
и Row
существует разница в том, как веса используются для расчета ширины элемента. Для Rows
вес зависит от всех элементов в Row
. При использовании FlowRow
вес зависит от элементов в строке, в которую помещен элемент , а не от всех элементов в контейнере FlowRow
.
Например, если у вас есть 4 элемента, которые расположены в строке, каждый из которых имеет разный вес 1f, 2f, 1f
и 3f
, общий вес составит 7f
. Оставшееся пространство в строке или столбце будет разделено на 7f
. Затем ширина каждого элемента будет рассчитываться по формуле: weight * (remainingSpace / totalWeight)
.
Вы можете использовать комбинацию элементов Modifier.weight
и max с FlowRow
или FlowColumn
для создания макета в виде сетки. Этот подход полезен для создания адаптивных макетов, которые подстраиваются под размер вашего устройства.
Есть несколько различных примеров того, чего можно достичь, используя веса. Одним из примеров является сетка, в которой элементы имеют одинаковый размер, как показано ниже:
Чтобы создать сетку элементов одинакового размера, вы можете сделать следующее:
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) } }
Важно отметить, что если вы добавите еще один элемент и повторите его 10 раз вместо 9, последний элемент займет весь последний столбец, поскольку общий вес всей строки составит 1f
:
Вы можете комбинировать веса с другими Modifiers
такими как Modifier.width(exactDpAmount), Modifier.aspectRatio(aspectRatio)
или Modifier.fillMaxWidth(fraction)
. Все эти модификаторы работают вместе, чтобы обеспечить адаптивное изменение размеров элементов внутри FlowRow
(или FlowColumn
).
Вы также можете создать чередующуюся сетку элементов разных размеров, где два элемента занимают половину ширины каждый, а один элемент занимает всю ширину следующего столбца:
Вы можете добиться этого с помощью следующего кода:
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)) } } }
Дробный размер
Используя Modifier.fillMaxWidth(fraction)
вы можете указать размер контейнера, который должен занимать элемент. Это отличается от того, как работает Modifier.fillMaxWidth(fraction)
при применении к Row
или Column
, поскольку элементы Row/Column
занимают процент от оставшейся ширины, а не от ширины всего контейнера.
Например, следующий код дает разные результаты при использовании FlowRow
vs 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()
и fillMaxRowHeight()
Применение Modifier.fillMaxColumnWidth()
или Modifier.fillMaxRowHeight()
к элементу внутри FlowColumn
или FlowRow
гарантирует, что элементы в том же столбце или строке займут ту же ширину или высоту, что и самый большой элемент в столбце/строке.
Например, в этом примере FlowColumn
используется для отображения списка десертов Android. Вы можете увидеть разницу в ширине каждого элемента, когда Modifier.fillMaxColumnWidth()
применяется к элементам, а также когда его нет и элементы переносятся.
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) ) } } }
| |
Не задано изменение ширины (обертывание элементов) |
Рекомендуется для вас
- Примечание. Текст ссылки отображается, когда JavaScript отключен.
- Основы составления макета
- ConstraintLayout в Compose
- Действия редактора {:#editor-actions}