Expanded: что это, принцип работы во Flutter

Автор: IT Sectr Опубликовано: 2026-07-03 Время чтения: 6 мин

Expanded — виджет Flutter, который заставляет дочерний элемент заполнять всё доступное пространство в Flex-контейнере. Когда Row или Column распределяют место между детьми, Expanded забирает свободное пространство после учёта негибких элементов. По данным официальной документации Flutter (2026), Expanded — один из самых используемых layout-виджетов: он применяется в процентовке интерфейсов, построении карточек, списков и панелей. Главное его преимущество — автоматический расчёт ширины или высоты на основе flex-коэффициента без явного указания размеров.

Главное

  • Expanded — layout-виджет, растягивающий ребёнка на всё свободное место в Row, Column или Flex
  • Flex-фактор определяет, какую долю свободного пространства получит каждый Expanded
  • Expanded отличается от Flexible тем, что принудительно заполняет всё доступное место
  • Stack не поддерживает Expanded, только Row, Column и Flex
  • Ошибка при использовании Expanded вне Flex-контейнера вызывает LayoutException

Что такое Expanded

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 vs Flexible: ключевые отличия

Expanded и Flexible — оба распределяют пространство в Flex-контейнерах, но ведут себя принципиально по-разному. Разница заключается в свойстве fit, которое определяет, может ли ребёнок быть меньше доступного места.

Expanded имеет жёсткую модель поведения: его fit равен FlexFit.tight. Это означает, что дочерний виджет получает constraints, равные доступному пространству — ни больше, ни меньше. Если ребёнок меньше, он растягивается. Если больше — он сжимается. Flexible использует FlexFit.loose, позволяя дочернему элементу быть любого размера в пределах выделенного пространства.

На практике: если внутри Row находятся два Expanded с flex=1, каждый займёт ровно половину ширины. Если заменить их на Flexible с fit.loose, каждый ребёнок может быть меньше половины, если его собственный размер меньше — оставшееся место останется пустым.

Вывод: используйте Expanded для строгих пропорциональных макетов, Flexible — когда ребёнок может быть меньше доступного места. Если не уверены — начинайте с Expanded, оно даёт более предсказуемое поведение.

Flex-фактор: как распределяется пространство

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 для интерфейсов с узкой навигацией.

Примеры кода с Expanded

Пример 1 демонстрирует базовое использование Expanded в Row для создания трёх равных колонок.

dart
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-факторов для создания макета с боковой панелью и основным контентом.

dart
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 позволяет создавать как горизонтальные, так и вертикальные пропорциональные раскладки.

Типовые ошибки при использовании Expanded

Ошибка 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, и избегайте вложенности без явных размеров.

Часто задаваемые вопросы

Чем Expanded отличается от SizedBox.expand?

SizedBox.expand принудительно растягивает ребёнка на размеры, заданные внешними constraints, но не участвует в flex-распределении. Expanded работает только внутри Flex-контейнеров и учитывает flex-фактор при распределении свободного пространства между детьми.

Можно ли использовать Expanded внутри Stack?

Нет. Stack не является Flex-контейнером, и использование Expanded внутри него вызовет LayoutException. Для растягивания детей в Stack используйте Positioned.fill или BoxConstraints.expand.

Что произойдёт, если не указать flex-фактор?

По умолчанию flex=1. Все Expanded без явного flex получат равные доли свободного пространства. Если в Row три Expanded без flex, каждый займёт ровно треть доступного места.

Как сделать Expanded только по ширине, но не по высоте?

Поместите Expanded в Row для растягивания по горизонтали. Для вертикального растягивания используйте Expanded внутри Column. Если нужно ограничить размеры, оберните Expanded или его ребёнка в SizedBox.

Работает ли Expanded с Wrap или Flex виджетами?

Expanded работает с Flex, включая Row и Column как его подклассы. Wrap не является Flex-контейнером и не поддерживает Expanded. Для распределения пространства в Wrap используйте другими методами, например RunAlignment.

Итоги

  • Expanded — виджет для принудительного растягивания ребёнка на всё доступное пространство в Flex-контейнере
  • Flex-фактор определяет пропорцию распределения свободного места между несколькими Expanded
  • Отличие от Flexible: Expanded использует tight fit (обязательное заполнение), Flexible — loose fit (опциональное)
  • Ошибка при размещении Expanded вне Row, Column или Flex вызывает LayoutException
  • Адаптивность: пропорции макета сохраняются при изменении размеров экрана автоматически
  • Рекомендация: используйте Expanded как основной инструмент для колоночных и панельных макетов во Flutter

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также