Column, Row и Box

Разбираем три кита раскладки в Compose: вертикальный Column, горизонтальный Row и наслаивающий Box.

Column размещает дочерние элементы сверху вниз, Row — слева направо, Box накладывает их друг на друга.

Column — вертикально

Column ставит детей друг под другом. Это самый частый контейнер для экрана:

Column {
    Text("Строка 1")
    Text("Строка 2")
    Text("Строка 3")
}

ASCII-результат

+-----------+
| Строка 1  |
| Строка 2  |
| Строка 3  |
+-----------+

По умолчанию Column занимает по высоте ровно столько, сколько нужно содержимому, и прижимает детей к верхнему краю. Чтобы он растянулся на весь экран, ему дают Modifier.fillMaxSize(), а распределение детей задают через verticalArrangement — об этом в следующем уроке.

Row — горизонтально

Row ставит детей в ряд:

Row {
    Text("A")
    Text("B")
    Text("C")
}
+-----------+
| A  B  C   |
+-----------+

Box — наслоение

Box кладёт детей друг на друга, как стопку. Порядок в коде задаёт порядок слоёв: первый ребёнок — внизу, последний — сверху. Удобно для значка поверх картинки или текста по центру фона:

Box {
    Image(painter = bg, contentDescription = null)
    Text("Поверх картинки")
}

У Box есть параметр contentAlignment, который выравнивает детей внутри: например, Alignment.Center поставит текст по центру картинки, а Alignment.BottomEnd — в правый нижний угол. Отдельным детям можно задать своё выравнивание через Modifier.align(...) — это работает только внутри Box.

Как работает под капотом

Раскладочные composable работают в два шага. Сначала фаза измерения: контейнер спрашивает у каждого ребёнка его желаемый размер. Затем фаза размещения: контейнер расставляет детей по своим правилам — Column вниз, Row вправо, Box в одну точку с наслоением. В отличие от старой View-системы Compose измеряет дерево за один проход, без дорогих повторных замеров.

Частые ошибки

  • Использовать Box там, где нужен Column — элементы наложатся друг на друга вместо списка.
  • Вкладывать множество Column в Column без необходимости — лишняя глубина дерева.
  • Забывать, что без модификаторов размера контейнер занимает ровно столько, сколько нужно содержимому (wrap content).

Итог

  • Column — вертикальная раскладка, Row — горизонтальная, Box — наслоение.
  • Раскладка идёт в два шага: измерение и размещение.
  • Контейнер по умолчанию подстраивается под размер содержимого.
Проверьте себя
1. Как Column располагает дочерние элементы?
AСлева направо
BСверху вниз, друг под другом
CДруг на друга с наслоением
DПо диагонали
2. Для чего удобен Box?
AДля вертикального списка
BДля наслоения элементов друг на друга, например текста поверх картинки
CДля горизонтального ряда
DТолько для отступов