Widgets ohne State
Dauer: 40 Minuten
- Widgets sind UI-Komponenten
- Styles verwenden
- Checkbox und ListView einbauen
Ziel: Umgang mit stateless Widgets vertiefen
In Android hatten wir es mit Composables zu tun, in Flutter heißen die UI-Komponenten Widgets.
Stateless Widgets
Ein stateless Widget ist eine Klasse, die von StatelessWidget
erbt und die Methode build
implementiert. Wir sehen dies in unserem
Code sowohl mit der Klasse MyApp
als auch mit der Klasse
MyHomePage
:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Code weggelassen
// return Widget
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Code weggelassen
// return Widget
}
}
Ein stateless Widget (StatelessWidget
) hat keinen eigenen
veränderlichen State, aber seine Darstellung kann sich jederzeit
ändern, wenn sich seine Eingaben/Abhängigkeiten ändern — dann wird
build() erneut ausgeführt und ein neuer UI-Baum erzeugt.
TodoItem
als StatelessWidget
Wir erstellen nun die Klasse TodoItem
als stateless Widget
in einer neuen Datei lib/todo_item.dart
:
// Achtung: neue Datei lib/todo_item.dart !
import 'package:flutter/material.dart';
class TodoItem extends StatelessWidget {
final String title;
const TodoItem({super.key, required this.title});
@override
Widget build(BuildContext context) {
return Text(title);
}
}
TodoItem
wird in der Klasse MyHomePage
verwendet, dazu
müssen wir zunächst die Datei todo_item.dart
importieren:
import 'package:flutter/material.dart';
// Achtung: Import der neuen Datei lib/todo_item.dart !
import 'package:todosflutter2025/todo_item.dart';
void main() {
runApp(const MyApp());
}
// Code weggelassen
// In der Klasse MyHomePage:
body: const Column(
children: [
TodoItem(title: 'Einkaufen'), // anstatt Text-Widget
TodoItem(title: 'Kochen'),
TodoItem(title: 'Sport'),
],
),
// Code weggelassen
Styles in TodoItem
In Flutter gibt es viele Möglichkeiten, Styles zu definieren. Hier ein paar Beispiele (Vorschlag kam von ChatGPT):
import 'package:flutter/material.dart';
class TodoItem extends StatelessWidget {
final String title;
const TodoItem({super.key, required this.title});
@override
Widget build(BuildContext context) {
final textStyle = Theme.of(context).textTheme.bodyLarge;
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Text(
title,
style: textStyle,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
);
}
}
Theme.of(context).textTheme.bodyLarge
holt den
Standard-Fließtext-Stil aus dem aktuellen Material-Theme. Der Text
übernimmt dadurch Theme-Eigenschaften (z. B. Schriftfamilie, Größe,
Farbe) und reagiert auf Light/Dark sowie Textskalierung.
Voraussetzung: ein Theme im Baum (z. B. via MaterialApp).
EdgeInsets.symmetric(vertical: 2.0)
gibt den Innenabstand
(Padding) vor: oben 2.0 und unten 2.0 logische Pixel (insgesamt 4.0
vertikal).
Checkbox in TodoItem
Wir können das TodoItem
-Widget erweitern, um eine Checkbox
hinzuzufügen:
import 'package:flutter/material.dart';
class TodoItem extends StatelessWidget {
final String title;
const TodoItem({super.key, required this.title});
@override
Widget build(BuildContext context) {
final textStyle = Theme.of(context).textTheme.bodyLarge;
return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Row(
children: [
Checkbox(
value: false,
onChanged: (bool? value) {
/* to be implemented */
},
),
Text(
title,
style: textStyle,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
],
),
);
}
}
Wir implementieren die Methode onChanged
später, wenn wir
stateful
Widgets behandeln.
Mit einer weiteren Anpassung wollen wir das ganze TodoItem
antippbar machen:
import 'package:flutter/material.dart';
class TodoItem extends StatelessWidget {
final String title;
const TodoItem({super.key, required this.title});
@override
Widget build(BuildContext context) {
final textStyle = Theme.of(context).textTheme.bodyLarge;
return CheckboxListTile(
value: false,
onChanged: (bool? value) {
/* to be implemented */
},
title: Text(
title,
style: textStyle,
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
controlAffinity: ListTileControlAffinity.leading,
);
}
}
Hierzu verwenden wir das CheckboxListTile
-Widget, das
ein Material Design-Element ist und eine Checkbox mit einem Titel
kombiniert. Damit haben wir unseren Code vereinfacht und die
Antippbarkeit des gesamten Listenelements erreicht.
Es fällt auf, dass wir in Flutter weniger Import-Anweisungen benötigen als in der nativen Android-Entwicklung mit Kotlin.
TodoList
-Widget mit ListView
Schließlich ersetzen wir Column
für unsere drei statischen
Todos durch ein ListView
-Widget, um die TodoListe durch ein
besseres Listen-Widget für mögliche große Todolisten zu optimieren
und u.a. scrollbar zu machen.
Dazu erstellen wir zunächst eine weiteres stateless Widget
in einer neuen Datei lib/todo_list.dart
:
import 'package:flutter/material.dart';
import 'package:todosflutter2025/todo_item.dart';
class TodoList extends StatelessWidget {
const TodoList({super.key});
@override
Widget build(BuildContext context) {
return ListView(
children: const [
TodoItem(title: 'Einkaufen'),
TodoItem(title: 'Kochen'),
TodoItem(title: 'Sport'),
],
);
}
}
In lib/main.dart
ersetzen wir den Import vom TodoItem
mit
TodoList
und verwenden das neue Widget in der MyHomePage
-Klasse:
import 'package:flutter/material.dart';
// Achtung: folgenden Import anpassen!
import 'package:todosflutter2025/todo_list.dart';
// Code weggelassen
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Todo-App'),
),
body: const TodoList(), // Column durch TodoList ersetzt
floatingActionButton: FloatingActionButton(
onPressed: () => debugPrint('Todo hinzufügen'),
tooltip: 'Todo hinzufügen',
child: const Icon(Icons.add),
),
);
}
}
Zusammenfassung
In Flutter haben wir nun stateless Widgets kennengelernt, die
als Dart-Klassen implementiert werden, von StatelessWidget
erben
und die Methode build
implementieren. Es gibt viele vordefinierte
Widgets in Flutter für UI-Komponenten, Styles, Layout usw..
Geschachtelte Widgets ergeben eine Baumstruktur, die das UI
repräsentiert. Auch wenn in nativer Android-Entwicklung mit
Kotlin und Compose die UI-Komponenten als Funktionen (Composables)
definiert werden, gibt es viele Parallelen zwischen den beiden
Frameworks.
Mehr zu Widgets in der Flutter-Dokumentation:
PAUSE
spätestens hier eine Pause einlegen