Expanded — виджет Flutter, который заставляет дочерний элемент заполнять всё доступное пространство в Flex-контейнере. Когда Row или Column распределяют место между детьми, Expanded забирает свободное пространство после учёта негибких элементов. По данным официальной документации Flutter (2026), Expanded — один из самых используемых layout-виджетов: он применяется в процентовке интерфейсов, построении карточек, списков и панелей. Главное его преимущество — автоматический расчёт ширины или высоты на основе flex-коэффициента без явного указания размеров.
Главное
Expanded — это виджет-обёртка, который принимает child и заставляет его расширяться, чтобы заполнить доступное пространство в Flex-контейнере (Row, Column, Flex). Expanded не имеет собственного визуального представления — он только управляет constraints, передаваемыми дочернему элементу.
В основе Expanded лежит механизм Flex, предоставляемый фреймворком Flutter. Когда Row или Column вычисляют размеры своих детей, они сначала выделяют место негибким элементам (обычным виджетам с фиксированными размерами), а оставшееся пространство распределяют между Expanded и Flexible-детьми пропорционально их flex-факторам.
Expanded использует Flexible.fit = FlexFit.tight. Это означает, что ребёнок Expanded обязан занять всё выделенное ему пространство, даже если его собственный размер меньше. В отличие от Flexible с Fit.loose, где ребёнок может быть меньше выделенной области, Expanded принудительно растягивает содержимое.
Вывод: Expanded — основной инструмент для создания пропорциональных макетов во Flutter. Используйте его, когда нужно чтобы элемент гарантированно занял всю доступную ширину или высоту.
Expanded и Flexible — оба распределяют пространство в Flex-контейнерах, но ведут себя принципиально по-разному. Разница заключается в свойстве fit, которое определяет, может ли ребёнок быть меньше доступного места.
Expanded имеет жёсткую модель поведения: его fit равен FlexFit.tight. Это означает, что дочерний виджет получает constraints, равные доступному пространству — ни больше, ни меньше. Если ребёнок меньше, он растягивается. Если больше — он сжимается. Flexible использует FlexFit.loose, позволяя дочернему элементу быть любого размера в пределах выделенного пространства.
На практике: если внутри Row находятся два Expanded с flex=1, каждый займёт ровно половину ширины. Если заменить их на Flexible с fit.loose, каждый ребёнок может быть меньше половины, если его собственный размер меньше — оставшееся место останется пустым.
Вывод: используйте Expanded для строгих пропорциональных макетов, Flexible — когда ребёнок может быть меньше доступного места. Если не уверены — начинайте с Expanded, оно даёт более предсказуемое поведение.
Flex-фактор (параметр flex) — числовое значение, определяющее долю доступного пространства, которую получит Expanded. По умолчанию flex=1, что означает равномерное распределение между всеми Expanded-детьми.
Алгоритм распределения работает в три шага. Первый: Flutter вычисляет intrinsic size всех негибких детей. Второй: оставшееся пространство делится на сумму всех flex-факторов. Третий: каждый Expanded получает долю, равную его flex-фактору, умноженному на размер одной единицы flex.
Например, Row шириной 300px содержит два Expanded: первый с flex=2, второй с flex=1. Свободное пространство (300px минус негибкие дети) делится на 3 части. Первый получает 2/3, второй — 1/3. Если негибких детей нет, первый получит 200px, второй — 100px.
Flex-фактор может быть любым положительным целым числом. Значение 0 — особый случай: Expanded с flex=0 ведёт себя как обычный негибкий виджет, занимая минимальное пространство по размеру ребёнка. Это поведение эквивалентно отсутствию Expanded.
Вывод: flex-фактор — ключ к построению гибких макетов. Используйте соотношения 1:1 для равных колонок, 2:1 для панелей с основной и боковой областью, 3:1 для интерфейсов с узкой навигацией.
Пример 1 демонстрирует базовое использование Expanded в Row для создания трёх равных колонок.
Row(
children: [
Expanded(
child: Container(
color: Colors.red,
),
),
Expanded(
child: Container(
color: Colors.green,
),
),
Expanded(
child: Container(
color: Colors.blue,
),
),
],
)
В этом примере три Expanded с flex=1 (по умолчанию) делят ширину Row поровну. Контейнеры растягиваются на всю высоту, заданную Row, и занимают равные доли. Такой подход удобен для создания колоночных макетов с пропорциональным распределением.
Пример 2 показывает использование разных flex-факторов для создания макета с боковой панелью и основным контентом.
Row(
children: [
Expanded(
flex: 1,
child: Container(
color: Colors.grey.200,
child: const Center(
child: Text('Sidebar'),
),
),
),
Expanded(
flex: 3,
child: Container(
color: Colors.white,
child: const Center(
child: Text('Content Area'),
),
),
),
],
)
Второй пример создаёт типичный layout с боковой панелью (25%) и основной областью (75%). flex=1 и flex=3 дают соотношение 1:3. При изменении ширины экрана пропорции сохраняются автоматически — это основа адаптивных интерфейсов.
Вывод: Expanded с разными flex-факторами — стандартный инструмент для построения адаптивных макетов. Сочетание Expanded в Column позволяет создавать как горизонтальные, так и вертикальные пропорциональные раскладки.
Ошибка 1: использование Expanded вне Row, Column или Flex. Если поместить Expanded напрямую в Stack, ListView или другой контейнер, не являющийся Flex, Flutter выбрасывает LayoutException с сообщением "Expanded widgets must be placed inside Flex widgets". Решение: проверять родительский виджет — только Row, Column или Flex.
Ошибка 2: размещение Expanded внутри ListView без указания shrinkWrap. ListView по умолчанию имеет бесконечную высоту в направлении прокрутки, и Expanded не может рассчитать свою долю. Решение: использовать shrinkWrap: true или оборачивать ListView в SizedBox с фиксированной высотой.
Ошибка 3: несколько Expanded с суммарным flex, превышающим доступное пространство. Если внутри Row с ограниченной шириной находятся Expanded, а также виджеты с большим intrinsic size, может возникнуть overflow. Решение: проверять минимальные размеры негибких детей и при необходимости использовать FittedBox или Flex fit.
Ошибка 4: вложенные Expanded в Column внутри Row. Если Expanded внутри Column содержит другой Expanded внутри Row, может возникнуть конфликт constraints. Решение: ограничивать глубину вложенности или использовать ConstrainedBox для явного задания размеров на промежуточных уровнях.
Вывод: Expanded требует правильного родительского контекста. Всегда проверяйте, что Expanded находится непосредственно в Row, Column или Flex, и избегайте вложенности без явных размеров.
Часто задаваемые вопросы
SizedBox.expand принудительно растягивает ребёнка на размеры, заданные внешними constraints, но не участвует в flex-распределении. Expanded работает только внутри Flex-контейнеров и учитывает flex-фактор при распределении свободного пространства между детьми.
Нет. Stack не является Flex-контейнером, и использование Expanded внутри него вызовет LayoutException. Для растягивания детей в Stack используйте Positioned.fill или BoxConstraints.expand.
По умолчанию flex=1. Все Expanded без явного flex получат равные доли свободного пространства. Если в Row три Expanded без flex, каждый займёт ровно треть доступного места.
Поместите Expanded в Row для растягивания по горизонтали. Для вертикального растягивания используйте Expanded внутри Column. Если нужно ограничить размеры, оберните Expanded или его ребёнка в SizedBox.
Expanded работает с Flex, включая Row и Column как его подклассы. Wrap не является Flex-контейнером и не поддерживает Expanded. Для распределения пространства в Wrap используйте другими методами, например RunAlignment.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также