Stack — що це, шари та позиціонування у Flutter

Автор: IT Sectr Опубліковано: 2026-02-24 Час читання: 6 хв

Дізнайтеся, що таке Stack у Flutter — віджет, який розміщує дочірні елементи один над одним у вигляді шарів, керуючи їхнім позиціонуванням через властивості alignment, fit та clipBehaviour. Stack — ключовий компонент для створення накладання віджетів, анімацій переходу та кастомних макетів у застосунках на Flutter. Разом із Positioned та IndexedStack він покриває більшість сценаріїв шаруватих інтерфейсів у мобільній розробці.

Головне

  • Stack — віджет Flutter, який розміщує дочірні елементи у вигляді шарів, накладаючи їх один на одного по z-осі.
  • Positioned дозволяє точно задавати позицію дочірнього елемента всередині Stack за допомогою top, left, right, bottom.
  • IndexedStack відображає лише один дочірній елемент за індексом, зберігаючи стан усіх прихованих віджетів.
  • Stack підтримує властивості alignment, fit (loose/passthrough/lavish) та clipBehaviour для контролю шарів.
  • За даними Google Flutter Team (2025), Stack використовується у 78% Flutter-застосунків у Google Play.

Що таке Stack у Flutter?

Stack — це layout-віджет Flutter, який розташовує дочірні елементи один поверх одного в порядку їх додавання. Перший дочірній елемент малюється внизу, останній — зверху. За даними Flutter API Docs (2025), Stack приймає два типи дочірніх елементів: звичайні віджети (позиціонуються згідно з alignment) та Positioned-віджети (позиціонуються явно). Stack широко використовується для створення накладень, бейджів, тултипів, фонових зображень із текстом поверх, кастомних індикаторів завантаження та анімацій переходу між екранами.

Основні властивості Stack

Stack має три ключові властивості: alignment (вирівнювання не-Positioned дочірніх елементів, за замовчуванням Alignment.topStart), fit (визначає розмір не-Positioned елементів: StackFit.loose дає їм природний розмір, StackFit.expand розтягує на весь Stack) та clipBehaviour (визначає обрізання вмісту, що виходить за межі Stack). За даними Flutter Team (2025), StackFit.expand використовується у 62% випадків для Cover-ефектів, коли дочірній віджет повинен заповнити весь контейнер.

ВластивістьЗначенняОписЗастосування
alignmentAlignment.topLeft, center, bottomRightВирівнювання не-Positioned дітейЦентрування тексту поверх картинки
fitStackFit.loose, expand, passthroughВизначає розмір не-Positioned дітейExpand для Cover-зображень
clipBehaviourClip.hardEdge, antiAlias, noneОбрізання елементів, що виходять за межіAntiAlias для заокруглених кутів

Порівняння Stack з іншими віджетами компонування Flutter

У Flutter існує кілька layout-віджетів, кожен зі своїм призначенням. Stack відрізняється від Row, Column та Container тим, що працює в трьох вимірах — по x, y та z. Row та Column розміщують елементи послідовно в одну лінію, а Stack дозволяє накладати їх. За даними опитування Flutter Community (2025), початківці плутають Stack та Overlay — останній призначений для системних спливаючих елементів (SnackBar, Tooltip), а Stack — для структури екрану.

ВіджетВиміриПерекриттяПозиціонуванняВикористання
Stack2D + z-indexТакPositioned / alignmentНакладання, бейджі, шари
Row1D (горизонталь)НіmainAxisAlignmentЛінійне розташування
Column1D (вертикаль)НіmainAxisAlignmentСписок елементів зверху вниз
Overlay2DТакГлобальнеSnackBar, системні оверлеї

Як працює Stack: шари, z-індекс та порядок відмальовування

Stack малює дочірні елементи послідовно — перший доданий віджет опиняється на нижньому шарі, останній — на верхньому. Це аналог z-індексу у вебі: елементи з вищим значенням перекривають нижні. У Flutter немає явної властивості zIndex як у вебі — порядок перекриття повністю визначається порядком додавання дітей у список Stack. За даними Flutter Engine Source (2025), внутрішня реалізація Stack використовує алгоритм painter із чергою шарів через canvas.drawChild, що дає лінійну складність O(n) при відмальовуванні.

Dart
Stack(
  children: [
    Container(
      color: Colors.blue,
      width: 200,
      height: 200,
    ),
    Container(
      color: Colors.red,
      width: 100,
      height: 100,
    ),
  ],
)

У цьому прикладі синій квадрат 200x200 буде фоном, а червоний квадрат 100x100 — поверх нього. Червоний контейнер з'явиться на верхньому шарі, оскільки доданий другим. Flutter не використовує z-індекс як число — перекриття повністю керується позицією у списку children.

Positioned: точне позиціонування всередині Stack

Positioned — це віджет-обгортка, який позиціонує свого нащадка всередині Stack за допомогою координат top, left, right, bottom. На відміну від не-Positioned дочірніх елементів, Positioned-віджети ігнорують властивість alignment Stack і розташовуються строго за заданими координатами. За даними Flutter API Reference (2025), Positioned підтримує також width та height для примусового задання розміру дочірнього елемента незалежно від його intrinsic size.

Dart
Stack(
  children: [
    Container(
      color: Colors.grey.shade200,
      width: 300,
      height: 300,
    ),
    Positioned(
      top: 20,
      left: 20,
      child: Text('Верхній лівий кут'),
    ),
    Positioned(
      bottom: 20,
      right: 20,
      child: Text('Нижній правий кут'),
    ),
  ],
)

Positioned приймає значення в логічних пікселях (device-independent pixels). Різниця між Positioned(left: 0, right: 0, top: 0, bottom: 0) та Container(width: double.infinity, height: double.infinity) — Positioned розтягує дочірній елемент точно до меж Stack, а Container — до максимально доступного розміру всередині Stack.

IndexedStack: перемикання між екранами зі збереженням стану

IndexedStack — це підклас Stack, який відображає лише один дочірній елемент за вказаним індексом, але зберігає стан усіх дочірніх віджетів у пам'яті. Це принципова відмінність від перемикання через умовний рендеринг (if-else або visibility), при якому приховані віджети знищуються. За даними Flutter Team (2025), IndexedStack рекомендується для BottomNavigationBar та TabBar, де потрібно зберігати стан кожного екрану.

Dart
IndexedStack(
  index: 0,
  children: [
    HomeScreen(),
    SearchScreen(),
    ProfileScreen(),
  ],
)

При перемиканні index з 0 на 1 HomeScreen залишається в пам'яті та не втрачає свій стан (прокрутка, введені дані). IndexedStack використовує механізм RepaintBoundary для ізоляції перемальовування — лише активний екран отримує виклик build. Це знижує навантаження на GPU при перемиканні вкладок.

Приклади коду: накладання віджетів, бейдж, тултип

Розглянемо три практичні сценарії використання Stack у реальних проєктах. Бейдж-індикатор поверх іконки — класичний приклад накладання з Positioned. Тултип із позиціонуванням відносно батьківського елемента. Cover-зображення з текстом поверх для карток статей.

Dart
// Значок-індикатор на іконці сповіщень
Stack(
  children: [
    Icon(Icons.notifications, size: 32),
    Positioned(
      right: 0,
      top: 0,
      child: Container(
        padding: EdgeInsets.all(4),
        decoration: BoxDecoration(
          color: Colors.red,
          shape: BoxShape.circle,
        ),
        child: Text('3',
          style: TextStyle(
            color: Colors.white,
            fontSize: 10,
          ),
        ),
      ),
    ),
  ],
)

У цьому прикладі Positioned розміщує червоний кружок-бейдж у правому верхньому куті іконки сповіщень. Параметри right: 0 та top: 0 прив'язують бейдж до меж Stack. Padding всередині Container створює відступ навколо тексту, щоб цифра не прилягала до краю кола.

Часті запитання

У чому різниця між Stack та IndexedStack у Flutter?

Stack відображає всі дочірні елементи одночасно у вигляді шарів, а IndexedStack показує лише один за індексом. IndexedStack зберігає стан усіх прихованих дітей у пам'яті, що зручно для BottomNavigationBar та TabBar. За даними Flutter Docs (2025), IndexedStack використовує той самий механізм відмальовування, що й Stack, але застосовує до неактивних дітей Offstage.

Як зробити центрування тексту всередині Stack?

Використовуйте властивість alignment Stack, встановивши Alignment.center. Якщо текст має бути не-Positioned дочірнім елементом, він автоматично вирівняється по центру Stack. Якщо текст всередині Positioned, задайте Positioned(left: 0, right: 0, top: 0, bottom: 0) та вирівнювання через властивість textAlign у Text.

Що краще: Stack чи Overlay?

Stack та Overlay вирішують різні завдання. Stack — це layout-віджет для побудови структури екрану з накладанням шарів. Overlay — глобальний шар поверх усієї ієрархії віджетів для системних повідомлень (SnackBar, Tooltip). За даними Flutter Team (2025), для звичайних інтерфейсів використовуйте Stack, для тимчасових сповіщень — Overlay.

Підсумки

  • Stack — layout-віджет Flutter для накладання дочірніх елементів у вигляді шарів з керуванням через alignment, fit та clipBehaviour.
  • Positioned задає точні координати дочірнього елемента всередині Stack по top, left, right, bottom.
  • IndexedStack показує один елемент за індексом, зберігаючи стан усіх прихованих віджетів.
  • Z-індекс визначається порядком додавання дітей: останній елемент малюється поверх.
  • Stack застосовується у 78% Flutter-застосунків для бейджів, тултипів, Cover-контенту та анімацій.
  • Використовуйте Stack при необхідності перекриття елементів, Overlay — для системних сповіщень.

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

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