Row, Column и Flex-вёрстка

Row выстраивает виджеты в строку, Column — в столбец; выравнивание задаётся по двум осям.

Суть: Row и Column раскладывают детей вдоль главной оси, а mainAxisAlignment и crossAxisAlignment управляют выравниванием по главной и поперечной осям.

За кулисами Row и Column устроены на основе модели Flex — той же идеи, что и flexbox в вебе, но выраженной виджетами. Дети могут быть жёсткими (занимают столько, сколько просят) или гибкими (делят свободное место). Этим гибким поведением управляют Expanded и Flexible, которые мы затронем подробнее, но уже сейчас полезно держать в голове: пространство ряда распределяется в два этапа — сначала жёсткие дети, затем остаток между гибкими.

Любой экран — это комбинация горизонтальных и вертикальных рядов. Шапка с аватаркой слева и именем справа — это Row. Лента карточек сверху вниз — это Column. Оба берут список детей в свойстве children и расставляют их вдоль своей оси.

Column(
  mainAxisAlignment: MainAxisAlignment.center,     // по вертикали
  crossAxisAlignment: CrossAxisAlignment.start,     // по горизонтали
  children: const [
    Text('Заголовок'),
    Text('Подзаголовок'),
    Icon(Icons.star),
  ],
)

Row(
  mainAxisAlignment: MainAxisAlignment.spaceBetween,
  children: const [
    Icon(Icons.menu),
    Text('Название'),
    Icon(Icons.search),
  ],
)

Ключ к пониманию — две оси. У Row главная ось горизонтальна, у Column — вертикальна. mainAxisAlignment двигает детей вдоль главной оси, crossAxisAlignment — поперёк.

Как работают оси под капотом

Запомнить легко: main = по направлению виджета, cross = поперёк. Значения MainAxisAlignment — это способы распределить свободное место: start, center, end, spaceBetween (промежутки между детьми), spaceAround, spaceEvenly. Flutter сначала измеряет детей, потом распределяет остаток пространства согласно выбранному выравниванию.

  Column (главная ось — вертикаль |)
  +-------------------+
  | [Заголовок]       |   crossAxisAlignment.start
  | [Подзаголовок]    |   (прижато влево)
  | [звезда]          |
  +-------------------+    main двигает вверх/вниз/центр

  Row (главная ось — горизонталь -->)
  +-----------------------------------+
  |[меню]      [Название]    [поиск]  |  spaceBetween
  +-----------------------------------+
   main --> распределяет по ширине; cross — по высоте
# Модель распределения по главной оси (spaceBetween и center)
def layout(children, alignment, total=30):
    used = sum(len(c) for c in children)
    free = max(0, total - used)
    if alignment == 'center':
        pad = free // 2
        return ' ' * pad + ' '.join(children)
    if alignment == 'spaceBetween' and len(children) > 1:
        gap = free // (len(children) - 1)
        return (' ' * gap).join(children)
    return ' '.join(children)

print('|' + layout(['A', 'B', 'C'], 'center') + '|')
print('|' + layout(['A', 'B', 'C'], 'spaceBetween') + '|')

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

  • Переполнение (overflow). Если детей в Row больше, чем ширины, появляются жёлто-чёрные полосы. Лечится Expanded или прокруткой.
  • Путать оси. В Column mainAxisAlignment — это вертикаль, а не горизонталь.
  • Ждать центрирования без указания размера. Column по умолчанию занимает всю высоту, Row — всю ширину; это влияет на выравнивание.

Best practices

  • Запомните мнемонику: main = вдоль виджета, cross = поперёк.
  • Для гибкого распределения ширины/высоты используйте Expanded и Flexible (следующий урок).
  • Если содержимое может не влезть — оборачивайте в прокручиваемый виджет, не надейтесь, что поместится.

Частый практический приём — комбинировать Row и Column во вложенные структуры. Карточка товара — это Column из картинки сверху и Row снизу с названием слева и ценой справа. Почти любой реальный макет раскладывается на такие вложенные ряды и столбцы. Тренируйте взгляд: глядя на дизайн, мысленно режьте его на горизонтальные и вертикальные полосы — это и будет ваша структура из Row и Column.

Итог: Row и Column — это скелет любой вёрстки Flutter. Освойте две оси и выравнивания — и вы сможете расположить что угодно. Дальше добавим гибкость через Expanded и контейнеры.

Проверьте себя
1. В виджете Column за выравнивание по вертикали отвечает...
AcrossAxisAlignment
BmainAxisAlignment
CtextAlign
DPadding
2. Что означает MainAxisAlignment.spaceBetween?
AПрижать всё к центру
BРаспределить детей с равными промежутками между ними, крайние — у краёв
CСкрыть промежутки
DРастянуть один виджет