Flexible — widget Flutter, który zarządza tym, jak element podrzędny zajmuje dostępne miejsce w kontenerze Flex. W przeciwieństwie do Expanded, Flexible nie zmusza dziecka do wypełnienia całego przydzielonego obszaru — widget podrzędny może być mniejszy, a pozostałe miejsce pozostaje puste. Według oficjalnej dokumentacji Flutter (2026), Flexible jest niezbędny w scenariuszach, gdzie wymagane jest elastyczne rozmieszczenie przestrzeni bez wymuszonego rozciągania: przyciski z minimalną szerokością, bloki tekstowe z naturalnym rozmiarem i elementy z intrinsic constraints.
Najważniejsze
Flexible — to widget-opakowanie, zapewniający elementowi podrzędnemu elastyczne miejsce w kontenerze Flex. Flexible, podobnie jak Expanded, uczestniczy w rozdzielaniu wolnego miejsca, ale z kluczową różnicą: dziecko Flexible może zająć mniej miejsca, niż mu przydzielono, jeśli jego własny rozmiar jest mniejszy niż dostępny.
Flexible używa Flex-algorytmu Flutter do obliczania dostępnej przestrzeni. Najpierw framework odpytuje wszystkie nieelastyczne dzieci (widgety bez Flexible/Expanded) i oblicza ich intrinsic size. Pozostałe miejsce jest dzielone pomiędzy elastyczne dzieci proporcjonalnie do ich flex-factor. Po przydzieleniu miejsca Flexible sprawdza fit — jeśli jest loose, do elementu podrzędnego stosowane jest ograniczenie „nie więcej niż przydzielone”, pozwalając mu pozostać małym.
Cecha Flexible: jeśli widget podrzędny ma własne minimalne rozmiary (na przykład Text z długim łańcuchem znaków), Flexible przydziela mu żądane miejsce, a nie rozciąga go na siłę. To czyni Flexible niezastąpionym dla elementów, których rozmiar powinien być określany przez treść, a nie przez kontener.
Wniosek: używaj Flexible, gdy trzeba zarezerwować miejsce dla elementu, ale nie zmuszać go do rozciągania. To zachowuje naturalne rozmiary treści przy elastycznym rozmieszczeniu układu.
FlexFit — wyliczenie z dwóch wartości: tight i loose. Od wyboru fit zależy, czy widget podrzędny zostanie przymusowo rozciągnięty do rozmiarów przydzielonego miejsca.
FlexFit.tight: element podrzędny otrzymuje tight constraints — minimalny i maksymalny rozmiar są równe przydzielonemu miejscu. Dziecko musi zająć dokładnie tyle miejsca, ile przydzielił Flex-algorytm. Jeśli dziecko jest mniejsze — zostaje rozciągnięte. Jeśli większe — zostaje ściśnięte. Zachowanie identyczne z Expanded.
FlexFit.loose: element podrzędny otrzymuje loose constraints — minimalny rozmiar wynosi 0, maksymalny jest równy przydzielonemu miejscu. Dziecko może być dowolnego rozmiaru od 0 do maximum. Jeśli dziecko jest małe (na przykład Text z krótkim łańcuchem znaków), zajmuje swoją naturalną szerokość, a reszta miejsca pozostaje pusta.
Wniosek: FlexFit.loose — wybór dla bloków tekstowych i elementów z naturalnym rozmiarem. FlexFit.tight — dla sztywnych układów kolumnowych, gdzie wszystkie elementy powinny być tej samej szerokości lub wysokości.
Flexible i Expanded wyglądają podobnie, ale rozwiązują różne zadania. Expanded zawsze rozciąga dziecko na pełną dostępną przestrzeń. Flexible może pozostawić puste miejsce wokół dziecka, jeśli rozmiar treści jest mniejszy niż przydzielona część.
Scenariusz dla Flexible: wewnątrz Row znajdują się dwa przyciski. Pierwszy — „Kup” (krótki tekst), drugi — „Dodaj do koszyka” (długi tekst). Z Expanded oba przyciski rozciągną się na równą szerokość, a krótki tekst będzie miał ogromne marginesy. Z Flexible każdy przycisk zajmie szerokość swojego tekstu, a wolne miejsce pozostanie pomiędzy nimi lub na brzegach.
Scenariusz dla Expanded: wewnątrz Column znajdują się trzy karty, które powinny zajmować równą wysokość niezależnie od zawartości. Expanded równomiernie dzieli dostępną wysokość, a każda karta rozciąga się do jednakowego rozmiaru. Flexible z loose tutaj nie zadziała — mała karta pozostanie mała, naruszając jednolity design.
Wniosek: wybieraj Flexible, gdy zawartość określa rozmiar elementu i puste miejsce wokół niego jest dopuszczalne. Wybieraj Expanded, gdy wszystkie elementy powinny być jednakowego rozmiaru niezależnie od treści.
Przykład 1 demonstruje podstawowe użycie Flexible z FlexFit.loose w Row.
Row(
children: [
Flexible(
fit: FlexFit.loose,
child: Container(
color: Colors.amber,
child: const Text('krótki'),
),
),
Flexible(
fit: FlexFit.loose,
child: Container(
color: Colors.cyan,
child: const Text('długi tekst do demo'),
),
),
],
)
W przykładzie oba Flexible z loose fit. Pierwszy kontener z krótkim tekstem zajmuje swoją naturalną szerokość. Drugi z długim — swoją. Row przydziela każdemu połowę dostępnej szerokości, ale loose fit pozwala kontenerom być mniejszymi, a wolne miejsce pozostaje puste pomiędzy nimi.
Przykład 2 — porównanie Flexible z Tight i Loose fit w Column.
Column(
children: [
Flexible(
fit: FlexFit.tight,
child: const Card(
child: ListTile(
title: Text('Tight — rozciągnięty na pełną wysokość'),
),
),
),
const SizedBox(
height: 8,
),
Flexible(
fit: FlexFit.loose,
child: const Card(
child: ListTile(
title: Text('Loose — naturalna wysokość'),
),
),
),
],
)
W Column pierwszy Flexible (tight) rozciąga Card na połowę dostępnej wysokości. Drugi Flexible (loose) — Card zajmuje wysokość według zawartości, a reszta miejsca pozostaje pusta. Wizualnie widać, jak tight wymusza wypełnienie obszaru, a loose zachowuje kompaktowy rozmiar.
Wniosek: w kodzie produkcyjnym Flexible z loose stosuje się do pól formularzy, przycisków i bloków tekstowych. Flexible z tight — odpowiednik Expanded, używany do równomiernego rozdzielania.
Błąd 1: użycie Flexible poza kontenerem Flex. Podobnie jak Expanded, Flexible zgłasza LayoutException, jeśli nie znajduje się wewnątrz Row, Column lub Flex. Rozwiązanie: zawsze sprawdzaj łańcuch rodzicielski widgetów.
Błąd 2: pomylenie Flexible i Expanded. Programiści często używają Expanded, gdy potrzebny jest Flexible z loose fit, i odwrotnie. Rezultat: Expanded rozciąga element z krótkim tekstem, tworząc duże puste pola. Rozwiązanie: jeśli rozmiar elementu może być mniejszy niż przydzielone miejsce — używaj Flexible(fit: FlexFit.loose).
Błąd 3: zerowy flex-factor. Flexible z flex=0 zachowuje się jak nieelastyczny widget, co może być nieoczywiste. Programista oczekuje elastycznego zachowania, ale element zajmuje minimalny rozmiar. Rozwiązanie: flex powinien być ≥1 do aktywnego rozdzielania przestrzeni.
Błąd 4: Flexible wewnątrz ScrollView bez ograniczenia rozmiaru. Jeśli Flexible znajduje się w Column wewnątrz SingleChildScrollView, scroll-kontener daje nieskończoną przestrzeń i flex-rozdział nie działa. Rozwiązanie: ogranicz rozmiar scroll-kontenera przez SizedBox lub ConstrainedBox.
Wniosek: Flexible wymaga takiej samej uwagi do kontekstu rodzicielskiego jak Expanded. Różnica tylko w fit — wybieraj go świadomie w zależności od zadania.
Często zadawane pytania
Expanded — to Flexible z ustalonym fit=tight. Różnica polega na tym, że Expanded ma sztywne powiązanie z wypełnieniem całej dostępnej przestrzeni, podczas gdy Flexible może użyć loose fit do zachowania naturalnego rozmiaru dziecka.
Dla przycisków z różną długością tekstu używaj Flexible(fit: FlexFit.loose). Każdy przycisk zajmie szerokość według zawartości i nie będzie między nimi dysproporcji. Expanded zrówna wszystkie przyciski do tej samej szerokości.
Ustaw fit: FlexFit.tight — Flexible będzie zmuszać dziecko do wypełnienia całej przydzielonej przestrzeni. W tym trybie Flexible jest w pełni identyczny z Expanded pod względem zachowania.
Tak, jeśli dziecko jest większe niż przydzielone miejsce. Flexible przekazuje constraints z maksymalnym rozmiarem równym części Flex-kontenera. Jeśli dziecko przekracza ten rozmiar, zostaje ściśnięte w ramach constraints.
Tak, Flexible działa z dowolnym kontenerem Flex, w tym Row, Column i podstawowym widgetem Flex z dowolnym direction. Flex pozwala zadawać niestandardowe kierunki przez mainAxisAlignment i crossAxisAlignment.
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ż