Dart Kurs Naechste Lektion

Lektion 09 - Flutter Counter-App

Aus Dart wird eine grafische App

Nach den Dart-Grundlagen geht es jetzt in Flutter weiter. Du nimmst das neue Standard-Counter-Projekt, analysierst den Code und baust daraus eine deutlich komplexere Counter-App mit mehreren Buttons.

1. Projektziel

Du erstellst ein neues Flutter-Projekt, legst daraus ein neues public Repository an und veraenderst die Counter-App so, dass sie nicht mehr nur einen FloatingActionButton nutzt.

01

Neues Flutter-Projekt anlegen und den Startcode analysieren.

02

Projekt als neues public Repository veroeffentlichen.

03

FloatingActionButton entfernen.

04

Mehrere unterschiedliche Counter-Buttons einbauen.

05

Code so strukturieren, dass die oberste Ebene schnell lesbar ist.

2. Was ist Flutter?

Flutter ist ein Framework, mit dem du grafische Oberflaechen baust. Der Code wird in Dart geschrieben. Eine Flutter-App besteht aus Widgets. Ein Widget ist ein Baustein der Oberflaeche, zum Beispiel Text, Button, Spalte, Zeile oder eine ganze Seite.

Text('Hallo Flutter')
ElevatedButton(...)
Column(...)
Row(...)

3. Der Counter im Startprojekt

Im Standardprojekt gibt es eine Zahl _counter. Wenn der Button gedrueckt wird, ruft Flutter setState auf. Dadurch wird die Zahl geaendert und die Oberflaeche neu gezeichnet.

int _counter = 0;

void _incrementCounter() {
  setState(() {
    _counter++;
  });
}

4. Planung fuer die neue App

Auch bei Flutter-Aufgaben planst du zuerst die Logik. Die Oberflaeche ist neu, aber die Denkweise bleibt gleich: Zustand, Aktionen, Ausgabe.

Setze counter auf 0

Zeige die aktuelle Zahl an

Wenn Button "+1" gedrueckt wird:
  Erhoehe counter um 1

Wenn Button "-1" gedrueckt wird:
  Senke counter um 1

Wenn Button "+2" gedrueckt wird:
  Erhoehe counter um 2

Wenn Button "-2" gedrueckt wird:
  Senke counter um 2

Wenn Button "x2" gedrueckt wird:
  Verdopple counter

Wenn Button "/2" gedrueckt wird:
  Halbiere counter

Zeichne die Oberflaeche nach jeder Aenderung neu

5. Column und Row verstehen

Column ordnet Widgets von oben nach unten an. Row ordnet Widgets von links nach rechts an. Fuer eine Button-Gruppe kannst du mehrere Rows in eine Column legen.

Column

Column(
  children: [
    Text('Counter'),
    Text('0'),
    Row(...),
  ],
)

Row

Row(
  children: [
    ElevatedButton(...),
    ElevatedButton(...),
  ],
)

Wichtig: children ist eine Liste. Darin stehen die Widgets, die angezeigt werden.

6. FloatingActionButton entfernen

Im Startprojekt steht im Scaffold normalerweise ein floatingActionButton. Diese Zeile entfernst du, weil deine Buttons direkt im Layout stehen sollen.

Vorher

Scaffold(
  appBar: AppBar(...),
  body: Center(...),
  floatingActionButton: FloatingActionButton(
    onPressed: _incrementCounter,
    child: const Icon(Icons.add),
  ),
)

Nachher

Scaffold(
  appBar: AppBar(...),
  body: Center(
    child: CounterView(...),
  ),
)

7. Aktionen fuer den Counter

Jede Aenderung am Counter muss in setState passieren. Sonst aendert sich zwar vielleicht ein Wert, aber Flutter zeichnet die Oberflaeche nicht neu.

void _changeCounter(int value) {
  setState(() {
    _counter += value;
  });
}

void _doubleCounter() {
  setState(() {
    _counter *= 2;
  });
}

void _halveCounter() {
  setState(() {
    _counter = (_counter / 2).round();
  });
}

Bei / entsteht in Dart ein double. Darum wird mit round() wieder eine ganze Zahl daraus.

8. Extract Widget

Wenn die oberste Ebene schnell lesbar sein soll, darf nicht alles in einer riesigen build-Methode stehen. Du lagerst Teile in eigene Widgets aus. Das nennt man Extract Widget.

class CounterActionButton extends StatelessWidget {
  const CounterActionButton({
    super.key,
    required this.label,
    required this.onPressed,
  });

  final String label;
  final VoidCallback onPressed;

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: onPressed,
      child: Text(label),
    );
  }
}
label

Text, der auf dem Button steht.

onPressed

Funktion, die beim Klick ausgefuehrt wird.

required

Dieser Parameter muss beim Erzeugen angegeben werden.

9. Parameter an Widgets uebergeben

Eigene Widgets werden flexibel, wenn du ihnen Werte uebergibst. So brauchst du nicht fuer jeden Button eine eigene Klasse.

CounterActionButton(
  label: '+1',
  onPressed: () => _changeCounter(1),
)

CounterActionButton(
  label: '-2',
  onPressed: () => _changeCounter(-2),
)

() => _changeCounter(1) bedeutet: Fuehre diese Funktion erst aus, wenn der Button gedrueckt wird.

10. Beispiel-Struktur fuer lesbaren Code

Die oberste Ebene soll schnell lesbar sein. Eine gute Struktur koennte so aussehen:

MyCounterPage
  Scaffold
    AppBar
    Body
      CounterDisplay
      CounterControls
        CounterActionButton
        CounterActionButton
        CounterActionButton

Dadurch erkennt man oben sofort: Die Seite hat Anzeige und Steuerung. Die Details liegen in kleineren Widgets.

11. Orientierungscode

Dieser Code ist eine mögliche Richtung. Schreibe ihn nicht blind ab: Lies zuerst die Struktur, markiere Widgets und ueberlege, welche Aufgabe jedes Widget hat.

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

  @override
  State<CounterPage> createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> {
  int _counter = 0;

  void _changeCounter(int value) {
    setState(() {
      _counter += value;
    });
  }

  void _doubleCounter() {
    setState(() {
      _counter *= 2;
    });
  }

  void _halveCounter() {
    setState(() {
      _counter = (_counter / 2).round();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Counter App')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            CounterDisplay(value: _counter),
            CounterControls(
              onPlusOne: () => _changeCounter(1),
              onMinusOne: () => _changeCounter(-1),
              onPlusTwo: () => _changeCounter(2),
              onMinusTwo: () => _changeCounter(-2),
              onDouble: _doubleCounter,
              onHalf: _halveCounter,
            ),
          ],
        ),
      ),
    );
  }
}

12. Uebungen

  1. Lege ein neues Flutter-Projekt an und finde main.dart.
  2. Markiere im Startcode Scaffold, AppBar, body und FloatingActionButton.
  3. Schreibe eine kurze Planung fuer alle Counter-Aktionen.
  4. Entferne den FloatingActionButton und ersetze ihn durch Buttons im body.
  5. Nutze mindestens eine Column und zwei Row-Bereiche.
  6. Extrahiere mindestens ein eigenes Widget fuer wiederverwendbare Buttons.
  7. Uebergib dem Button-Widget mindestens label und onPressed als Parameter.
  8. Variiere die Buttons optisch: Text, Farbe, Icon, Groesse oder Stil.

Sauberer Lernweg: Erst Startcode analysieren, dann Verhalten planen, dann Layout planen, dann Widgets extrahieren, danach optisch variieren.

Weiter zu Widgets & Layout