Научете какво е Stack във Flutter — уиджет, който поставя дъщерните един върху друг под формата на слоеве, управлявайки позиционирането им чрез свойствата alignment, fit и clipBehaviour. Stack е ключов компонент за създаване на наслагване на уиджети, анимации на преходи и персонализирани оформления в приложения на Flutter. Заедно с Positioned и IndexedStack покрива повечето сценарии за слоести интерфейси в мобилната разработка.
Основни точки
Stack е уиджет за оформление във Flutter, който поставя дъщерните елементи един върху друг в реда на добавянето им. Първият дъщерен елемент се рисува отдолу, последният — отгоре. Според Flutter API Docs (2025), Stack приема два типа дъщерни елементи: обикновени уиджети (позиционирани според alignment) и Positioned уиджети (изрично позиционирани). Stack се използва широко за създаване на наслагвания, значки, подсказки, фонови изображения с текст отгоре, персонализирани индикатори за зареждане и анимации на преходи между екрани.
Stack има три ключови свойства: alignment (подравняване на не-Positioned дъщерни елементи, по подразбиране Alignment.topStart), fit (определя размера на не-Positioned елементи: StackFit.loose им дава естествен размер, StackFit.expand ги разтяга върху целия Stack) и clipBehaviour (определя изрязването на съдържание, излизащо извън границите на Stack). Според Flutter Team (2025), StackFit.expand се използва в 62% от случаите за Cover ефекти, когато дъщерният уиджет трябва да запълни целия контейнер.
| Свойство | Стойности | Описание | Приложение |
|---|---|---|---|
| alignment | Alignment.topLeft, center, bottomRight | Подравняване на не-Positioned деца | Центриране на текст върху изображение |
| fit | StackFit.loose, expand, passthrough | Определя размера на не-Positioned деца | Expand за Cover изображения |
| clipBehaviour | Clip.hardEdge, antiAlias, none | Изрязване на елементи извън границите | AntiAlias за заоблени ъгли |
Във Flutter съществуват няколко уиджета за оформление, всеки със своето предназначение. Stack се различава от Row, Column и Container по това, че работи в три измерения — x, y и z. Row и Column поставят елементите последователно в една линия, докато Stack позволява наслагването им. Според проучване на Flutter Community (2025), начинаещите разработчици бъркат Stack с Overlay — последният е предназначен за системни изскачащи елементи (SnackBar, Tooltip), а Stack — за структура на екрана.
| Уиджет | Измерения | Наслагване | Позициониране | Употреба |
|---|---|---|---|---|
| Stack | 2D + z-index | Да | Positioned / alignment | Наслагване, значки, слоеве |
| Row | 1D (хоризонтално) | Не | mainAxisAlignment | Линейно подреждане |
| Column | 1D (вертикално) | Не | mainAxisAlignment | Списък от елементи отгоре надолу |
| Overlay | 2D | Да | Глобално | SnackBar, системни наслагвания |
Stack рисува дъщерните елементи последователно — първият добавен уиджет е на долния слой, последният — на горния. Това е аналог на z-индекса в уеб: елементите с по-висока стойност покриват по-ниските. Във Flutter няма изрично свойство zIndex като в уеб — редът на наслагване се определя изцяло от реда на добавяне на децата в списъка на Stack. Според Flutter Engine Source (2025), вътрешната реализация на Stack използва алгоритъм на художник с опашка от слоеве чрез canvas.drawChild, което дава линейна сложност O(n) при рисуване.
Stack(
children: [
Container(
color: Colors.blue,
width: 200,
height: 200,
),
Container(
color: Colors.red,
width: 100,
height: 100,
),
],
)
В този пример синият квадрат 200×200 ще бъде фон, а червеният квадрат 100×100 — върху него. Червеният контейнер ще се появи на горния слой, тъй като е добавен втори. Flutter не използва z-index като число — наслагването се контролира изцяло от позицията в списъка children.
Positioned е обвиващ уиджет, който позиционира своя наследник вътре в Stack с помощта на координатите top, left, right, bottom. За разлика от не-Positioned дъщерни елементи, Positioned уиджетите игнорират свойството alignment на Stack и се поставят стриктно според зададените координати. Според Flutter API Reference (2025), Positioned поддържа също width и height за принудително задаване на размера на дъщерния елемент независимо от присъщия му размер.
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 е подклас на Stack, който показва само един дъщерен елемент според указания индекс, но запазва състоянието на всички дъщерни уиджети в паметта. Това е основна разлика от превключването чрез условно рендиране (if-else или visibility), при което скритите уиджети се унищожават. Според Flutter Team (2025), IndexedStack се препоръчва за BottomNavigationBar и TabBar, където трябва да се запази състоянието на всеки екран.
IndexedStack(
index: 0,
children: [
HomeScreen(),
SearchScreen(),
ProfileScreen(),
],
)
При превключване на index от 0 на 1, HomeScreen остава в паметта и не губи състоянието си (превъртане, въведени данни). IndexedStack използва механизма RepaintBoundary за изолиране на прерисуването — само активният екран получава извикване build. Това намалява натоварването на GPU при превключване на раздели.
Нека разгледаме три практически сценария за използване на Stack в реални проекти. Значка за известия върху иконата — класически пример за наслагване с Positioned. Подсказка с позициониране спрямо родителския елемент. Cover изображение с текст отгоре за карти на статии.
// Значка индикатор на иконата за известия
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 показва само един по индекс. IndexedStack запазва състоянието на всички скрити деца в паметта, което е удобно за BottomNavigationBar и TabBar. Според Flutter Docs (2025), IndexedStream използва същия механизъм за рисуване като Stack, но прилага Offstage към неактивните деца.
Използвайте свойството alignment на Stack, като го настроите на Alignment.center. Ако текстът е не-Positioned дъщерен елемент, той автоматично ще се центрира в Stack. Ако текстът е вътре в Positioned, задайте Positioned(left: 0, right: 0, top: 0, bottom: 0) и подравняване чрез свойството textAlign на Text.
Stack и Overlay решават различни задачи. Stack е уиджет за оформление за изграждане на структура на екрана с наслагване на слоеве. Overlay е глобален слой над цялата йерархия от уиджети за системни съобщения (SnackBar, Tooltip). Според Flutter Team (2025), за обикновени интерфейси използвайте Stack, за временни известия — Overlay.
Обобщение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също