Dart Kurs Naechste Lektion

Lektion 11 - Flutter Widgets im Detail

Container, Expanded, Flexible und mehr sicher einsetzen

Nach der Widget-Einfuehrung geht es jetzt tiefer: Du lernst wichtige Flutter-Widgets kennen, die du fast in jeder App brauchst. Der Fokus liegt darauf, wann du welches Widget benutzt und welche Fehler dabei typisch sind.

1. Schnelluebersicht

Widget/KonzeptWofuer?
ContainerBox fuer Groesse, Farbe, Rahmen, Margin und Padding
ExpandedNimmt freien Platz in Row oder Column ein
FlexibleDarf freien Platz nutzen, muss ihn aber nicht komplett fuellen
SizedBoxFester Abstand oder feste Breite/Hoehe
PaddingInnenabstand um ein Kind-Widget
LayoutBuilderReagiert auf verfuegbaren Platz
FutureBuilderZeigt UI passend zu asynchronen Daten
TextStyleGestaltet Text: Groesse, Farbe, Gewicht, Abstand

2. Container

Container ist eine flexible Box. Du nutzt ihn, wenn ein Bereich eine Groesse, Hintergrundfarbe, Umrandung, Rundung oder Abstand bekommen soll.

Container(
  width: 180,
  height: 80,
  padding: const EdgeInsets.all(16),
  decoration: BoxDecoration(
    color: Colors.blue,
    borderRadius: BorderRadius.circular(12),
  ),
  child: const Text('Info Box'),
)
width / height

Legt feste Groesse fest, wenn das Elternlayout das erlaubt.

padding

Innenabstand zwischen Rand und Inhalt.

decoration

Farbe, Rahmen, Rundung oder Schatten.

child

Das Widget, das im Container liegt.

Typischer Fehler: color und decoration gleichzeitig direkt am Container setzen. Wenn du decoration nutzt, gehoert die Farbe dort hinein.

3. Padding

Padding gibt einem Widget Innenabstand. Es ist klarer als ein leerer Container, wenn du wirklich nur Abstand brauchst.

Padding(
  padding: const EdgeInsets.all(16),
  child: Text('Mit Abstand'),
)

Nutze Padding, wenn du keinen Rahmen, keine Farbe und keine feste Box brauchst.

4. SizedBox

SizedBox ist perfekt fuer feste Abstaende oder feste Groessen. Es ist sehr lesbar und wird haeufig zwischen Widgets eingesetzt.

Column(
  children: [
    Text('Oben'),
    SizedBox(height: 16),
    Text('Unten'),
  ],
)

Nutze SizedBox fuer einfachen Abstand statt komplizierter Leer-Widgets.

5. Expanded

Expanded funktioniert nur innerhalb von Row, Column oder aehnlichen Flex-Layouts. Es sagt: Dieses Kind soll den freien Platz ausfuellen.

Row(
  children: [
    Expanded(
      child: Container(color: Colors.blue),
    ),
    Expanded(
      child: Container(color: Colors.green),
    ),
  ],
)

In diesem Beispiel teilen sich beide Container den freien Platz gleichmaessig. Mit flex kannst du das Verhaeltnis veraendern.

Row(
  children: [
    Expanded(flex: 2, child: Text('Breiter')),
    Expanded(flex: 1, child: Text('Schmaler')),
  ],
)

Typischer Fehler: Expanded ausserhalb von Row oder Column verwenden. Dann meldet Flutter einen Parent-Data-Fehler.

6. Flexible

Flexible ist verwandt mit Expanded. Der Unterschied: Expanded zwingt das Kind, freien Platz zu fuellen. Flexible erlaubt dem Kind, flexibler mit dem Platz umzugehen.

Expanded

Expanded(
  child: Text('Fuellt Platz'),
)

Flexible

Flexible(
  child: Text('Darf kleiner bleiben'),
)

Faustregel: Nutze Expanded, wenn der Platz wirklich gefuellt werden soll. Nutze Flexible, wenn Inhalt natuerlicher wachsen oder kleiner bleiben darf.

7. TextStyle

TextStyle gestaltet Text. Du kannst Farbe, Groesse, Schriftgewicht, Zeilenhoehe, Ausrichtung und vieles mehr beeinflussen.

Text(
  'Flutter lernen',
  style: TextStyle(
    fontSize: 28,
    fontWeight: FontWeight.bold,
    color: Colors.blue,
    height: 1.3,
  ),
)
PropertyBedeutung
fontSizeTextgroesse
fontWeightSchriftgewicht, zum Beispiel FontWeight.bold
colorTextfarbe
heightZeilenhoehe als Faktor
letterSpacingAbstand zwischen Buchstaben

Wiederholte Textstile solltest du spaeter nicht ueberall kopieren, sondern in ein Theme oder eigene Konstanten auslagern.

8. LayoutBuilder

LayoutBuilder gibt dir Informationen ueber den Platz, den ein Widget gerade bekommt. Damit kannst du Layouts bauen, die auf kleine oder grosse Bereiche reagieren.

LayoutBuilder(
  builder: (context, constraints) {
    if (constraints.maxWidth < 600) {
      return Column(children: [
        Text('Kleines Layout'),
        Text('Unter dem Titel'),
      ]);
    }

    return Row(children: [
      Text('Grosses Layout'),
      Text('Neben dem Titel'),
    ]);
  },
)
constraints

Informationen ueber verfuegbare Breite und Hoehe.

maxWidth

Wichtiger Wert fuer responsive Entscheidungen.

builder

Funktion, die je nach Platz ein Widget zurueckgibt.

Nutze LayoutBuilder, wenn das Layout vom verfuegbaren Platz abhaengt, nicht nur von einer festen Bildschirmgroesse.

9. FutureBuilder

FutureBuilder ist fuer Daten, die erst spaeter ankommen. Zum Beispiel: Datei laden, API anfragen oder eine kuenstliche Wartezeit. Er zeigt je nach Zustand eine andere UI.

FutureBuilder<String>(
  future: loadName(),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      return CircularProgressIndicator();
    }

    if (snapshot.hasError) {
      return Text('Fehler beim Laden');
    }

    return Text(snapshot.data ?? 'Kein Name');
  },
)
future

Die spaeter fertige Aufgabe.

snapshot

Enthaelt Zustand, Daten oder Fehler.

waiting

Daten sind noch nicht da, zeige Ladeanzeige.

hasError

Beim Laden ist ein Fehler passiert.

data

Die geladenen Daten, wenn alles geklappt hat.

Typischer Fehler: Direkt snapshot.data! nutzen, obwohl Daten noch fehlen koennen. Erst Zustand und Fehler pruefen.

10. Layout-Planungsaufgabe

Aufgabe: Plane eine responsive Profilkarte. Auf kleinen Flaechen stehen Bild, Name, Beschreibung und Button untereinander. Auf grossen Flaechen stehen Bild und Text nebeneinander. Daten fuer den Namen kommen spaeter aus einem Future.

Starte das Laden des Namens

Wenn Daten noch laden:
  Zeige Ladeanzeige

Wenn Fehler beim Laden:
  Zeige Fehlermeldung

Wenn Name geladen:
  Pruefe verfuegbare Breite

  Wenn Breite kleiner als 600:
    Zeige Profilbild oben
    Zeige Name darunter
    Zeige Beschreibung darunter
    Zeige Button darunter

  Sonst:
    Zeige Profilbild links
    Zeige Name, Beschreibung und Button rechts
FutureBuilder

Plant Ladezustand, Fehlerzustand und fertige Daten.

LayoutBuilder

Entscheidet zwischen kleinem und grossem Layout.

Column

Nutze sie fuer kleine Flaechen.

Row

Nutze sie fuer grosse Flaechen.

Padding/SizedBox

Sorgen fuer lesbare Abstaende.

11. Kombiniertes Beispiel

Dieses Beispiel verbindet mehrere der heutigen Konzepte. Lies zuerst die Struktur, dann erst die Details.

FutureBuilder<String>(
  future: loadName(),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      return const CircularProgressIndicator();
    }

    if (snapshot.hasError) {
      return const Text('Fehler');
    }

    final name = snapshot.data ?? 'Gast';

    return LayoutBuilder(
      builder: (context, constraints) {
        final content = Container(
          padding: const EdgeInsets.all(16),
          decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.circular(16),
          ),
          child: Text(
            name,
            style: const TextStyle(
              fontSize: 24,
              fontWeight: FontWeight.bold,
            ),
          ),
        );

        if (constraints.maxWidth < 600) {
          return Column(children: [content]);
        }

        return Row(children: [
          Expanded(child: content),
          const SizedBox(width: 16),
          Flexible(child: Text('Profilbeschreibung')),
        ]);
      },
    );
  },
)

12. Uebungen

  1. Baue drei farbige Container in einer Row.
  2. Nutze Expanded, damit alle drei gleich breit werden.
  3. Aendere einen Bereich auf flex: 2 und beschreibe, was passiert.
  4. Ersetze ein Expanded durch Flexible und vergleiche das Verhalten.
  5. Erstelle einen Titel mit TextStyle.
  6. Nutze LayoutBuilder, um bei kleiner Breite eine Column und bei grosser Breite eine Row zu zeigen.
  7. Baue einen einfachen FutureBuilder, der nach kurzer Zeit Text anzeigt.
  8. Schreibe fuer jede Aufgabe zuerst eine kurze Layout-Planung.
Weiter zum Flutter Framework-Update