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

Берите минимум строк и столбцов, которого хватает для нужной раскладки. Больше десяти уровней вложенности на странице или в компоненте — сигнал, что часть дерева пора вынести в компонент.
Выравнивание
Главная ось
Главная ось — то направление, вдоль которого виджет расставляет потомков.
Row: главная ось горизонтальная, потомки идут слева направо.
Доступные значения Main Axis для Row:

Column: главная ось вертикальная, потомки идут сверху вниз.
Значения Main Axis для Column те же:

Главная ось определяет, как распределяется свободное место между потомками: собрать их в начале, развести по краям или разложить с равными промежутками.
Поперечная ось
Поперечная ось перпендикулярна главной и отвечает за выравнивание по второму направлению. Значений три: Start, Center, End.
Row: поперечная ось вертикальная — определяет положение потомков по высоте строки.

Column: поперечная ось горизонтальная — определяет положение потомков по ширине столбца.

Выравнивание в Stack
У Stack осей в этом смысле нет: потомки позиционируются относительно всей его площади. За это отвечает свойство Default Child Alignment — координаты X и Y.

Оси — то, из-за чего вёрстка чаще всего ведёт себя «не так»: элемент прижат к краю или растянут вопреки ожиданиям почти всегда из-за настроек Main Axis и Cross Axis родителя.
Expansion и Flex
Виджет, попавший внутрь Row или Column, получает дополнительные свойства Expansion и Flex. Они определяют, сколько свободного места он заберёт у родителя.
Expanded
Варианты Expansion:
-
Default — виджет не растягивается вдоль главной оси и занимает ровно столько, сколько требует содержимое.
-
Flexible — виджет может занять всё доступное место вдоль главной оси, но не обязан. По сути это «максимальная ширина, равная свободному месту»: если содержимое меньше, виджет останется меньше.
вниманиеОграничениеFlexible недоступен, если родительский Row не ограничен по ширине, а Column — по высоте.
-
Expanded — виджет забирает всё свободное место вдоль главной оси.

-
Поведение по умолчанию. Два потомка стоят рядом, каждый занимает ровно столько, сколько нужно его содержимому.
-
Один Expanded. Первый потомок (выделен красным) обёрнут в Expanded и забирает всё, что осталось после остальных: он растягивается, остальные сжимаются до минимума.
-
Все Expanded. Свободное место делится между потомками поровну, независимо от того, сколько занимает содержимое каждого.
-
Все Flexible. Похоже на предыдущий случай, но с одним отличием: Flexible позволяет виджету стать меньше выделенной доли, если содержимому столько не нужно.
Ещё один пример, уже про Flexible:

-
Слева у потомков 2 (фиолетовый) и 3 (зелёный) настройки по умолчанию — они держат свой естественный размер. Когда контейнер узкий, содержимое обрезается: сжиматься эти виджеты не умеют.
-
Справа те же потомки обёрнуты в Flexible и подстраиваются под ширину контейнера — растягиваются или сжимаются, и содержимое остаётся видимым на любом экране.
Flex
Флекс-фактор — целое число, задающее долю виджета относительно соседей. Место делится пропорционально сумме флекс-факторов всех потомков.
Без флекс-фактора потомок не растягивается: он занимает ровно столько, сколько требует содержимое.
С флекс-фактором виджет забирает свою долю свободного места. Если у одного потомка фактор 1, а у другого 2, второй займёт вдвое больше.

-
Потомок 2 (фиолетовый) с фактором 8 стабильно занимает большую часть строки.
-
У потомка 3 (зелёного) фактор меняется с 1 на 4 — он заметно расширяется, но всё равно уступает потомку 2.
Видеоразбор Expanded и Flexible:
Прокрутка
Свойство прокрутки у Row и Column решает, что делать, когда содержимое не помещается в отведённое место:
-
Allow Scrolling — содержимое может выходить за границы экрана или родителя, и до него можно доскроллить.
-
Do Not Allow Scrolling — содержимое обязано уместиться. Лишнее не отображается, а во время разработки вы увидите характерную жёлто-чёрную полосу переполнения.
Включённая прокрутка означает, что Row или Column обёрнут в SingleChildScrollView(). Этот виджет подстраивает размер и положение потомка под входящие ограничения и берёт на себя обработку жеста.
Расстояния
- Items Spacing — расстояние между соседними потомками в пикселях. Значение можно задать числом или взять из переменной.
Задавайте расстояние на родительском Row или Column, а не отступами у каждого потомка. Отступы разъезжаются, особенно там, где список собран вручную, а не сгенерирован.
-
Apply to Start & End — применить то же расстояние в начале и в конце: к промежуткам между потомками добавятся отступы по краям.
-
Start Spacing и End Spacing — отдельные значения для начала и конца, когда нужны поля, отличные от промежутков между элементами.