Widget-Grundlagen

20 MinutenDie Bausteine von Flutter kennenlernen

Flutter und Dart

Flutter ist ein Open-Source-Framework von Google für Apps auf Android, iOS, Web und Desktop aus einer Codebasis. Programmiert wird in Dart.

  • Flutter zeichnet die Oberfläche selbst, statt native UI-Elemente zu verwenden
  • dadurch sieht die App auf allen Plattformen gleich aus
  • Dart wird für Android und iOS in nativen Maschinencode kompiliert

Projekt in VS Code anlegen

Die Flutter-Dokumentation empfiehlt VS Code mit der Flutter-Extension.

  • Extension Flutter installieren (bringt Dart mit)
  • Command Palette → Flutter: New Project → Empty Application
  • Projektname: weather_flutter_tif24
  • Gerät unten rechts in der Statusleiste wählen, starten mit F5

Projektstruktur

Der Dart-Code liegt in lib/, nach Aufgaben in Ordner aufgeteilt.

lib/
├── main.dart
├── ui/          Screens und Widgets, ViewModels
├── model/       Datenmodell: City, CurrentWeather
└── data/        Datenquellen: Fake-Daten, Repositorys
    └── api/     DTOs für die API (ab Schritt 9)
pubspec.yaml     Name, Abhängigkeiten, Assets
android/ ios/ web/  Plattform-Projekte, selten angefasst

Widgets

In Flutter ist alles ein Widget: Text, Abstände, Layouts, ganze Screens.

Widgets

Hot Reload: Speichern genügt, die Änderung ist in unter einer Sekunde im laufenden Emulator.

  • Hot Reload (Speichern): Code neu laden, State bleibt erhalten
  • Hot Restart (⇧ ⌘ F5): App neu starten, State geht verloren
  • neuer Build nötig bei Änderungen an pubspec.yaml oder nativem Code

Layouts: Column, Row, Container

Widgets werden mit Layout-Widgets angeordnet.

  • Column: untereinander
  • Row: nebeneinander
  • Stack: übereinander
  • Container: Hintergrund, Rahmen, Abstände um ein Kind
  • SizedBox: fester Abstand, Spacer: freier Platz

Layouts: Column, Row, Container

Die Verschachtelung im Code entspricht der Verschachtelung auf dem Bildschirm.

Layout als verschachtelte Boxen: Bildschirm und Code haben denselben Aufbau
Layout als verschachtelte Boxen: Bildschirm und Code haben denselben Aufbau

Layouts: Column, Row, Container

Column(
  mainAxisSize: MainAxisSize.min,
  children: [
    Text('Lörrach', style: TextStyle(fontSize: 28)),
    Text('⛅', style: TextStyle(fontSize: 72)),
    Text('14 °C', style: TextStyle(fontSize: 48)),
    SizedBox(height: 16),
    Row(children: [Text('Wind: 8 km/h'), Spacer(), Text('Teilweise bewölkt')]),
  ],
)

Abstände und Hintergrund

Einen Modifier gibt es nicht. Abstände und Hintergrund sind Eigenschaften von Container oder eigene Widgets wie Padding.

Container(
  width: double.infinity,
  margin: const EdgeInsets.all(16),   // außen
  padding: const EdgeInsets.all(24),  // innen
  decoration: BoxDecoration(
    color: const Color(0xFFBBDEFB),
    borderRadius: BorderRadius.circular(24),
  ),
  child: const Column(/* von oben */),
)

Datenmodell mit Klassen

Statt fester Texte bekommen Widgets nun Daten über den Konstruktor.

class City {
  const City({
    required this.name,
    required this.latitude,
    required this.longitude,
  });

  final String name;
  final double latitude;
  final double longitude;
}

Datenmodell mit Klassen

Widgets sollten Daten über den Konstruktor erhalten und sie nicht eigenständig holen.

class CurrentWeatherCard extends StatelessWidget {
  const CurrentWeatherCard({super.key, required this.city, required this.weather});

  final City city;
  final CurrentWeather weather;

  @override
  Widget build(BuildContext context) {
    // Container und Column wie bisher, die Texte jetzt aus den Daten:
    // Text(city.name), Text(weather.condition.emoji), ...
  }
}

Scaffold und AppBar

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(title: Text(city.name)),
    body: SingleChildScrollView(
      child: CurrentWeatherCard(city: city, weather: weather),
    ),
  );
}