Dowiedz się, czym jest Stack we Flutter — widżet, który umieszcza elementy potomne jeden nad drugim w postaci warstw, zarządzając ich pozycjonowaniem za pomocą właściwości alignment, fit i clipBehaviour. Stack to kluczowy komponent do tworzenia nakładania widżetów, animacji przejść i niestandardowych układów w aplikacjach Flutter. Wraz z Positioned i IndexedStack pokrywa większość scenariuszy interfejsów warstwowych w programowaniu mobilnym.
Najważniejsze
Stack to widżet układu we Flutter, który umieszcza elementy potomne jeden na drugim w kolejności ich dodawania. Pierwszy element potomny jest rysowany na dole, ostatni — na górze. Według Flutter API Docs (2025), Stack przyjmuje dwa typy elementów potomnych: zwykłe widżety (pozycjonowane zgodnie z alignment) oraz widżety Positioned (pozycjonowane jawnie). Stack jest szeroko stosowany do tworzenia nakładek, znaczków, podpowiedzi, obrazów tła z tekstem na wierzchu, niestandardowych wskaźników ładowania oraz animacji przejść między ekranami.
Stack ma trzy kluczowe właściwości: alignment (wyrównanie nie-Positioned elementów potomnych, domyślnie Alignment.topStart), fit (określa rozmiar nie-Positioned elementów: StackFit.loose nadaje im naturalny rozmiar, StackFit.expand rozciąga na cały Stack) oraz clipBehaviour (określa przycinanie treści wychodzącej poza granice Stack). Według Flutter Team (2025), StackFit.expand jest używany w 62% przypadków do efektów Cover, gdy widżet potomny ma wypełnić cały kontener.
| Właściwość | Wartości | Opis | Zastosowanie |
|---|---|---|---|
| alignment | Alignment.topLeft, center, bottomRight | Wyrównanie nie-Positioned elementów potomnych | Centrowanie tekstu na obrazku |
| fit | StackFit.loose, expand, passthrough | Określa rozmiar nie-Positioned elementów potomnych | Expand dla obrazów Cover |
| clipBehaviour | Clip.hardEdge, antiAlias, none | Przycinanie elementów wychodzących poza granice | AntiAlias dla zaokrąglonych rogów |
We Flutter istnieje kilka widżetów układu, każdy z własnym przeznaczeniem. Stack różni się od Row, Column i Container tym, że działa w trzech wymiarach — x, y i z. Row i Column umieszczają elementy sekwencyjnie w jednej linii, podczas gdy Stack pozwala je nakładać. Według ankiety Flutter Community (2025), początkujący programiści mylą Stack z Overlay — ten ostatni jest przeznaczony dla systemowych elementów wyskakujących (SnackBar, Tooltip), a Stack — dla struktury ekranu.
| Widżet | Wymiary | Nakładanie | Pozycjonowanie | Zastosowanie |
|---|---|---|---|---|
| Stack | 2D + z-index | Tak | Positioned / alignment | Nakładanie, znaczki, warstwy |
| Row | 1D (poziomo) | Nie | mainAxisAlignment | Układ liniowy |
| Column | 1D (pionowo) | Nie | mainAxisAlignment | Lista elementów od góry do dołu |
| Overlay | 2D | Tak | Globalne | SnackBar, nakładki systemowe |
Stack rysuje elementy potomne sekwencyjnie — pierwszy dodany widżet znajduje się na dolnej warstwie, ostatni — na górnej. Jest to odpowiednik z-index w sieci: elementy z wyższą wartością przykrywają niższe. We Flutter nie ma jawnej właściwości zIndex jak w sieci — kolejność nakładania jest w pełni określona przez kolejność dodawania dzieci do listy Stack. Według Flutter Engine Source (2025), wewnętrzna implementacja Stack wykorzystuje algorytm malarza z kolejką warstw przez canvas.drawChild, co daje liniową złożoność O(n) podczas rysowania.
Stack(
children: [
Container(
color: Colors.blue,
width: 200,
height: 200,
),
Container(
color: Colors.red,
width: 100,
height: 100,
),
],
)
W tym przykładzie niebieski kwadrat 200×200 będzie tłem, a czerwony kwadrat 100×100 — na nim. Czerwony kontener pojawi się na górnej warstwie, ponieważ został dodany jako drugi. Flutter nie używa z-index jako liczby — nakładanie jest w pełni kontrolowane przez pozycję na liście children.
Positioned to widżet-opakowanie, który pozycjonuje swojego potomka wewnątrz Stack za pomocą współrzędnych top, left, right, bottom. W przeciwieństwie do nie-Positioned elementów potomnych, widżety Positioned ignorują właściwość alignment Stack i są rozmieszczane ściśle według podanych współrzędnych. Według Flutter API Reference (2025), Positioned obsługuje również width i height do wymuszenia rozmiaru elementu potomnego niezależnie od jego intrinsic size.
Stack(
children: [
Container(
color: Colors.grey.shade200,
width: 300,
height: 300,
),
Positioned(
top: 20,
left: 20,
child: Text('Górny lewy róg'),
),
Positioned(
bottom: 20,
right: 20,
child: Text('Dolny prawy róg'),
),
],
)
Positioned przyjmuje wartości w pikselach logicznych (device-independent pixels). Różnica między Positioned(left: 0, right: 0, top: 0, bottom: 0) a Container(width: double.infinity, height: double.infinity) — Positioned rozciąga element potomny dokładnie do granic Stack, a Container — do maksymalnego dostępnego rozmiaru wewnątrz Stack.
IndexedStack to podklasa Stack, która wyświetla tylko jeden element potomny według określonego indeksu, ale zachowuje stan wszystkich widżetów potomnych w pamięci. Jest to zasadnicza różnica w porównaniu z przełączaniem przez warunkowe renderowanie (if-else lub visibility), przy którym ukryte widżety są niszczone. Według Flutter Team (2025), IndexedStack jest zalecany dla BottomNavigationBar i TabBar, gdzie trzeba zachować stan każdego ekranu.
IndexedStack(
index: 0,
children: [
HomeScreen(),
SearchScreen(),
ProfileScreen(),
],
)
Przy przełączaniu index z 0 na 1 HomeScreen pozostaje w pamięci i nie traci swojego stanu (przewijanie, wprowadzone dane). IndexedStack wykorzystuje mechanizm RepaintBoundary do izolacji przerysowania — tylko aktywny ekran otrzymuje wywołanie build. Zmniejsza to obciążenie GPU podczas przełączania zakładek.
Rozważmy trzy praktyczne scenariusze użycia Stack w rzeczywistych projektach. Znaczek powiadomień na ikonie — klasyczny przykład nakładania z Positioned. Podpowiedź z pozycjonowaniem względem elementu nadrzędnego. Obraz Cover z tekstem na wierzchu dla kart artykułów.
// Znacznik powiadomień na ikonce
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,
),
),
),
),
],
)
W tym przykładzie Positioned umieszcza czerwone kółko-znaczek w prawym górnym rogu ikony powiadomień. Parametry right: 0 i top: 0 przypinają znaczek do granic Stack. Padding wewnątrz Container tworzy odstęp wokół tekstu, aby cyfra nie przylegała do krawędzi koła.
Często zadawane pytania
Stack wyświetla wszystkie elementy potomne jednocześnie w postaci warstw, podczas gdy IndexedStack pokazuje tylko jeden według indeksu. IndexedStack zachowuje stan wszystkich ukrytych dzieci w pamięci, co jest wygodne dla BottomNavigationBar i TabBar. Według Flutter Docs (2025), IndexedStack używa tego samego mechanizmu rysowania co Stack, ale stosuje do nieaktywnych dzieci Offstage.
Użyj właściwości alignment Stack, ustawiając Alignment.center. Jeśli tekst ma być nie-Positioned elementem potomnym, automatycznie zostanie wyśrodkowany w Stack. Jeśli tekst jest wewnątrz Positioned, ustaw Positioned(left: 0, right: 0, top: 0, bottom: 0) i wyrównanie przez właściwość textAlign w Text.
Stack i Overlay rozwiązują różne zadania. Stack to widżet układu do budowania struktury ekranu z nakładaniem warstw. Overlay to globalna warstwa nad całą hierarchią widżetów dla komunikatów systemowych (SnackBar, Tooltip). Według Flutter Team (2025), do zwykłych interfejsów używaj Stack, do tymczasowych powiadomień — Overlay.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również