Flutter Widgets — co to jest, drzewo widgetów i metoda build

Autor: IT Sectr Opublikowano: 2026-02-21 Czas czytania: 8 min

Flutter Widgets – podstawowe bloki budulcowe interfejsu użytkownika w frameworku Google Flutter, wydanym w stabilnej wersji 1.0 w grudniu 2018 roku. We Flutter wszystko jest widgetem: od ekranu i przycisku po odstęp i wyrównanie. Widgety tworzą drzewo (widget tree), które Flutter renderuje na własnym silniku Skia/Impeller, z pominięciem natywnych komponentów platformy. Według Google I/O (2025), Flutter jest używany w ponad 500 000 aplikacji w Google Play i App Store. Architektura Flutter dzieli widgety na StatelessWidget (niezmienne) i StatefulWidget (ze zmiennym stanem poprzez obiekt State).

Najważniejsze

  • Flutter Widgets – wszystkie elementy UI we Flutter: od ekranu i przycisku po odstęp i wyrównanie; framework nie używa natywnych komponentów platformy.
  • StatelessWidget – widget bez zmiennego stanu; wyświetla dane przekazane przez konstruktor i nie zmienia się po zbudowaniu (build).
  • StatefulWidget – widget ze zmiennym stanem, przechowywanym w oddzielnym obiekcie State, który przetrwa rebuildy.
  • Drzewo widgetów (widget tree) – hierarchia widgetów opisujących UI; Flutter przekształca je w Element Tree i Render Tree do renderowania.
  • BuildContext – kontekst budowy, zapewniający dostęp do pozycji widgeta w drzewie, motywu, MediaQuery i InheritedWidget.

Co to są Flutter Widgets?

Flutter Widgets – wszystkie elementy UI we frameworku Flutter, zaimplementowane jako niezmienne (immutable) klasy Dart. Widget to konfiguracja elementu UI: jego rozmiar, kolor, położenie, obsługa zdarzeń. W przeciwieństwie do Androida (XML + View) czy iOS (Storyboard + UIView), Flutter nie używa natywnych komponentów – wszystko jest rysowane przez silnik Skia (Android/iOS/Linux) lub Impeller (iOS/macOS) na Canvas. Zapewnia to jednakowy wygląd na wszystkich platformach bez rozbieżności platformowych. Flutter jest dostarczany z dwoma zestawami widgetów: Material Widgets (projekt Google Material Design 3 dla Androida/Web) i Cupertino Widgets (projekt Apple HIG dla iOS/macOS). Deweloper może łączyć oba zestawy w jednej aplikacji. Każdy widget ma metodę build(), zwracającą widget potomny lub ich kompozycję – w ten sposób budowane jest drzewo widgetów.

Trzy drzewa Flutter

Flutter operuje na trzech drzewach: Widget Tree (konfiguracja, tworzona przez programistę), Element Tree (dopasowanie widgeta do pozycji w drzewie, zarządzane przez framework), Render Tree (obiekty obliczające layout i wykonujące paint). Widget tworzy Element, który tworzy RenderObject. Element jest ponownie używany przy zmianie konfiguracji (rebuild) – to mechanizm optymalizacji Flutter: jeśli typ widgeta i key są zgodne, Element nie jest odtwarzany, a jedynie aktualizowana jest nowa konfiguracja. Zrozumienie trzech drzew to klucz do optymalizacji wydajności aplikacji Flutter.

StatelessWidget: niezmienne widgety

StatelessWidget – widget, który nie przechowuje stanu wewnętrznego. Przyjmuje parametry przez konstruktor i wyświetla je bez możliwości zmiany po zbudowaniu. StatelessWidget idealnie nadaje się do elementów statycznych: nagłówków, ikon, awatarów, list ze stałymi danymi. Metoda build() jest wywoływana raz przy tworzeniu i przy zmianie widgeta nadrzędnego. Ponieważ StatelessWidget nie ma stanu, nie wymaga oddzielnego obiektu State – build() jest zdefiniowany bezpośrednio w klasie widgeta.

dart
import 'package:flutter/material.dart';

class ProfileHeader extends StatelessWidget {
  final String name;
  final String avatarUrl;

  const ProfileHeader({super.key, required this.name, required this.avatarUrl});

  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        CircleAvatar(
          radius: 24,
          backgroundImage: NetworkImage(avatarUrl),
        ),
        const SizedBox(width: 12),
        Text(
          name,
          style: const TextStyle(
            fontSize: 18,
            fontWeight: FontWeight.bold,
          ),
        ),
      ],
    );
  }
}

ProfileHeader – StatelessWidget, przyjmujący name i avatarUrl przez konstruktor. CircleAvatar wyświetla awatar, Text – nazwę. Widget nie może zmienić tych wartości po utworzeniu. Użycie const konstruktora (const ProfileHeader) pozwala Flutter na ponowne wykorzystanie instancji widgeta przy rebuild rodzica – to mikrooptymalizacja zalecana dla wszystkich StatelessWidget.

StatefulWidget: widgety ze stanem

StatefulWidget – widget ze zmiennym stanem, który jest przechowywany w oddzielnym obiekcie State. Sam StatefulWidget jest niezmienny (immutable), tak jak StatelessWidget. Zmienna część jest wyodrębniona w State: State – obiekt, który jest tworzony raz i przetrwa wielokrotne rebuildy widgeta. Gdy stan się zmienia (setState()), Flutter wywołuje build() State, aktualizując UI. StatefulWidget jest używany do elementów interaktywnych: liczników, pól tekstowych, checkboxów, animacji, timerów.

dart
import 'package:flutter/material.dart';

class LikeButton extends StatefulWidget {
  const LikeButton({super.key});

  @override
  State<LikeButton> createState() => _LikeButtonState();
}

class _LikeButtonState extends State<LikeButton> {
  bool liked = false;
  int count = 42;

  void _toggleLike() {
    setState(() {
      liked = !liked;
      count += liked ? 1 : -1;
    });
  }

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: _toggleLike,
      child: Text(liked ? '♥ $count' : '♡ $count'),
    );
  }
}

LikeButton – StatefulWidget z klasą State _LikeButtonState. Pola liked i count to stan przechowywany w State i nie resetowany przy rebuild. setState() powiadamia Flutter o konieczności przebudowania UI. Flutter nie odtwarza State przy każdym rebuildzie rodzica – tylko przy zmianie konfiguracji (key lub typ widgeta). W IT Sectr używamy StatelessWidget do wyświetlania i StatefulWidget do komponentów interaktywnych, stosując zasadę minimalizacji StatefulWidget do granic mutacji.

Drzewo widgetów: od Widget do RenderObject

Widget Tree – hierarchiczna struktura widgetów opisująca UI aplikacji. Flutter przekształca Widget Tree w Element Tree: każdy Widget tworzy Element, który śledzi pozycję w drzewie i połączenie z RenderObject. Render Tree wykonuje layout (określanie rozmiarów i pozycji) oraz paint (renderowanie). Element to kluczowa warstwa optymalizacyjna: jeśli typ widgeta i key nie zmieniły się przy rebuild, Element jest ponownie używany, aktualizując konfigurację bez odtwarzania RenderObject. Zapewnia to wydajność Flutter przy wysokiej częstotliwości klatek (60/120 FPS).

dart
import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Flutter Widgety')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.flutter_dash, size: 80),
            const SizedBox(height: 16),
            const Text(
              'Witaj, Flutter!',
              style: TextStyle(fontSize: 24),
            ),
          ],
        ),
      ),
    );
  }
}

Drzewo widgetów HomeScreen: Scaffold → AppBar + Center → Column → [Icon, SizedBox, Text]. Scaffold – główny widget layoutu Material Design. Center centruje potomny Column. Column rozkłada dzieci pionowo z wyrównaniem do środka (mainAxisAlignment.center). Flutter oblicza layout od góry do dołu (constraints przekazywane od rodzica), a rozmiary od dołu do góry (sizedByParent lub sizing from children).

BuildContext: kontekst budowy i dostęp do drzewa

BuildContext – deskryptor pozycji widgeta w Element Tree. Każda metoda build() otrzymuje BuildContext, przez który widget może uzyskać dostęp do:MediaQuery (rozmiar ekranu, orientacja, gęstość pikseli, safe area), Theme (MaterialThemeData lub CupertinoThemeData), Navigator (stos nawigacyjny), ScaffoldMessenger (SnackBar), InheritedWidget (przekazywanie danych w dół drzewa). BuildContext nie powinien być przechowywany po zakończeniu build() ani używany poza kontekstem synchronicznym – prowadzi to do błędów «Scaffold.of() called with a context that does not contain a Scaffold». Zamiast przechowywania context używaj widgeta Builder lub wzorca InheritedWidget do dostępu do danych.

Key: identyfikacja widgeta w drzewie

Key – opcjonalny parametr konstruktora każdego widgeta (super.key). Key pomaga Flutter identyfikować widget przy zmianie kolejności/liczby elementów na liście. Bez key Flutter porównuje widgety według typu i pozycji; przy dodawaniu elementu do środka listy bez key Flutter ponownie używa Element dla niewłaściwego widgeta, powodując błędy stanu (StatefulWidget) i animacji. Używaj ValueKey (unikalny identyfikator) dla list, ObjectKey (na podstawie obiektu danych), UniqueKey (gwarantowana unikalność przy każdym rebuild – do wymuszonego odtworzenia).

Katalog widgetów Flutter: Material, Cupertino, Layout

Flutter SDK (stabilna wersja 3.3+, Dart 3+) zawiera 200+ wbudowanych widgetów, podzielonych na kategorie: Layout (Row, Column, Stack, Container, Expanded, Flexible, Wrap, GridView, ListView, CustomScrollView), Material Design (Scaffold, AppBar, Card, Drawer, BottomNavigationBar, FloatingActionButton, TabBar, Chip, DataTable), Cupertino (CupertinoPageScaffold, CupertinoNavigationBar, CupertinoButton, CupertinoTabBar), Painting & Effects (Opacity, DecoratedBox, ClipRect, Transform, BackdropFilter, ShaderMask), Async (FutureBuilder, StreamBuilder) i Accessibility (Semantics, MergeSemantics, ExcludeSemantics). Layout-widgety to podstawa każdego Flutter UI: Row dla sekwencji poziomych, Column dla pionowych, Stack dla nakładających się elementów, Container z BoxDecoration do dekorowania.

KategoriaKluczowe widgetyPrzeznaczenie
LayoutRow, Column, Stack, Container, Expanded, FlexiblePozycjonowanie i rozmiary elementów potomnych
MaterialScaffold, AppBar, Card, Drawer, FAB, TabBarKomponenty UI Material Design 3
CupertinoCupertinoPageScaffold, CupertinoNavigationBar, CupertinoButtonKomponenty stylizowane na iOS
PaintingOpacity, ClipRect, Transform, DecoratedBox, BackdropFilterEfekty wizualne i przycinanie
AsyncFutureBuilder, StreamBuilderAsynchroniczne ładowanie danych ze stanami UI
AccessibilitySemantics, MergeSemanticsSemantyczne oznaczanie dla czytników ekranu

Często zadawane pytania

Czym różni się StatelessWidget od StatefulWidget?

StatelessWidget nie ma stanu wewnętrznego – wszystkie dane są przekazywane przez konstruktor i nie zmieniają się. StatefulWidget przechowuje zmienny stan w oddzielnym obiekcie State, który przetrwa rebuildy. Zmiana stanu wywołuje setState(), a Flutter przebudowuje UI. Dla elementów niezmiennych używaj StatelessWidget; dla interaktywnych – StatefulWidget.

Czym jest BuildContext we Flutter?

BuildContext – deskryptor pozycji widgeta w Element Tree, przekazywany do metody build(). Przez context widget uzyskuje dostęp do MediaQuery, Theme, Navigator, ScaffoldMessenger i InheritedWidget. BuildContext nie powinien być przechowywany po zakończeniu build(). Do dostępu do danych używaj widgeta Builder lub InheritedWidget.

Czy trzeba znać Dart do pracy z Flutter?

Tak, Flutter używa Dart jako jedynego języka programowania. Dart jest statycznie typowanym językiem z null-safety, dźwiękowymi typami (sound null safety), extension methods i pattern matching. Na początek wystarczą podstawy Darta: klasy, funkcje, async/await, kolekcje. Dart jest kompilowany do kodu natywnego (AOT) przez Dart Native i do JavaScript (dla web) przez Dart2JS.

Czy Flutter jest tylko dla platform mobilnych?

Nie, Flutter obsługuje sześć platform: iOS, Android, Web, macOS, Windows, Linux. Ponad 90% kodu jest wspólne dla wszystkich platform. Adaptacje platformowe (kamera, system plików) są realizowane przez wtyczki lub platform channels. Dla desktopu Flutter używa powłoki okienkowej Flutter Desktop, dla web – silnika CanvasKit (WebGL) lub renderera HTML.

Jak Flutter zapewnia wydajność 60 FPS?

Flutter osiąga 60/120 FPS dzięki: własnemu silnikowi 2D (Skia/Impeller), braku natywnego bridge (w przeciwieństwie do React Native), trzem drzewom (Widget → Element → Render) z ponownym wykorzystaniem Element przy niezmiennym typie/key, algorytmowi layoutu z jednokierunkowym przebiegiem (constraints down, sizes up) oraz RepaintBoundary do izolacji przerysowywania poszczególnych stref ekranu.

Podsumowanie

  • Flutter Widgets – wszystkie elementy UI: od Scaffold do SizedBox; Flutter rysuje je sam na Skia/Impeller, nie używając natywnych komponentów.
  • StatelessWidget – widget bez stanu; build() zwraca UI na podstawie niezmiennych parametrów konstruktora.
  • StatefulWidget – widget ze zmiennym stanem w State; setState() wywołuje rebuild UI.
  • Trzy drzewa Flutter: Widget (konfiguracja) → Element (pozycja) → Render (layout + paint); Element jest ponownie używany dla wydajności.
  • BuildContext – pozycja widgeta w drzewie; dostęp do MediaQuery, Theme, Navigator, InheritedWidget.
  • Material i Cupertino – dwa zestawy widgetów dla Google Material Design 3 i Apple HIG.
  • Key (ValueKey, ObjectKey, UniqueKey) – identyfikacja widgeta przy zmianie kolejności/liczby na liście.

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.

Omów projekt

Przeczytaj również