Flutter: SnackBar und SnackBarAction verwenden
Zuletzt aktualisiert:
5 Min. Lesezeit

Eine SnackBar ist die kurze Meldung, die das Ergebnis einer Aktion mitteilt, ohne den Ablauf zu unterbrechen: Sie erscheint am unteren Bildschirmrand, bleibt einige Sekunden stehen und verschwindet von selbst. Wir nutzen sie für Hinweise wie „Gespeichert“, „Verbindung unterbrochen“ oder „Eintrag gelöscht“. Mit SnackBarAction lässt sich genau ein Button ergänzen, das bekannteste Beispiel ist „Rückgängig“.
Live-Demo
Sie können dieses Widget im interaktiven Beispiel unten ausprobieren:
💡 Falls das Beispiel oben nicht lädt, klicken Sie auf DartPad, um es in einem neuen Tab auszuführen.
Grundlegende Verwendung
Angezeigt wird eine SnackBar über den ScaffoldMessenger:
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Profil aktualisiert'),
),
);In älteren Tutorials steht noch Scaffold.of(context).showSnackBar(...). Diese Methode wurde aus Flutter entfernt; wer sie heute verwendet, erhält den Compilerfehler „The method 'showSnackBar' isn't defined for the type 'ScaffoldState'“. Weil der ScaffoldMessenger zur App gehört und nicht zu einem einzelnen Scaffold, bleibt die SnackBar sichtbar, auch wenn währenddessen die Seite wechselt. Genau das brauchen wir in Abläufen, in denen der Nutzer auf „Speichern“ tippt und auf der vorherigen Seite landet.
SnackBarAction verwenden
Fügt neben der Meldung einen einzelnen Button hinzu:
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text('Eintrag gelöscht'),
action: SnackBarAction(
label: 'RÜCKGÄNGIG',
onPressed: () {
// Aktion rückgängig machen
},
),
),
);Ein Tipp auf den Button schließt die SnackBar automatisch. Es gibt nur eine Aktion, und sie sollte kurz sein. Wer zwei Möglichkeiten anbieten muss, sucht keine SnackBar, sondern einen Dialog.
Wichtige Eigenschaften
| Eigenschaft | Beschreibung |
|---|---|
content |
Inhalt der SnackBar (meist Text) |
action |
Anklickbarer Button (SnackBarAction) |
duration |
Anzeigedauer (standardmäßig 4 Sekunden) |
backgroundColor |
Hintergrundfarbe |
behavior |
fixed oder floating |
shape |
Form (z. B. Eckenradius) |
margin |
Abstände im Floating-Modus |
showCloseIcon |
Ergänzt rechts ein Schließen-Symbol |
Floating SnackBar
Statt am unteren Rand zu kleben, schwebt die SnackBar mit Abstand zu den Rändern:
SnackBar(
content: const Text('Floating SnackBar'),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
margin: const EdgeInsets.all(16),
)Soll die ganze App so aussehen, gehört das ins Theme, statt es bei jedem Aufruf zu wiederholen: ThemeData(snackBarTheme: const SnackBarThemeData(behavior: SnackBarBehavior.floating)).
SnackBar mit Symbol
SnackBar(
content: Row(
children: const [
Icon(Icons.info, color: Colors.white),
SizedBox(width: 10),
Expanded(child: Text('Informationsmeldung')),
],
),
backgroundColor: Colors.blue,
)Das Expanded um den Text ist wichtig. Ohne es läuft die Row bei einer langen Meldung rechts über; den Grund erklärt der Beitrag zu Expanded.
SnackBar programmatisch schließen
showSnackBar gibt einen Controller zurück. Wollen wir die Meldung bei einem längeren Vorgang selbst schließen, setzen wir eine lange Dauer und rufen nach getaner Arbeit close() auf:
final snackBar = ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Wird geladen...'),
duration: Duration(minutes: 1),
),
);
// Schließen, sobald der Vorgang abgeschlossen ist
await someAsyncOperation();
snackBar.close();Wann verwenden – und wann nicht?
Eine SnackBar ist für Informationen gedacht, die der Nutzer auch verpassen darf. Ich unterscheide so:
- Verwenden als Bestätigung einer abgeschlossenen Aktion, bei Vorgängen, die sich rückgängig machen lassen, und bei vorübergehenden Netzwerkfehlern.
- Nicht verwenden, wenn der Nutzer etwas entscheiden muss. Die Meldung ist nach vier Sekunden weg; eine Frage wie die Löschbestätigung braucht einen AlertDialog.
- Nicht verwenden für dauerhafte Zustände. Hinweise wie „Sie sind offline“, die bis zur Lösung des Problems stehen bleiben müssen, passen besser in ein
MaterialBanner, das mitScaffoldMessenger.of(context).showMaterialBanner(...)angezeigt wird. - Nicht verwenden für Validierungsfehler in Formularen. „E-Mail ungültig“ gehört per
validatordirekt unter das Feld, damit niemand suchen muss, welches Feld falsch ist.
Häufige Fehler
1. Meldungen stauen sich in der Warteschlange
Symptom: Der Nutzer tippt fünfmal schnell auf einen Button, die SnackBars erscheinen nacheinander, und die letzte steht zwanzig Sekunden später immer noch da.
Ursache: Der ScaffoldMessenger reiht Meldungen ein; eine neue wartet, bis die vorherige fertig ist.
Lösung: Die aktuelle ausblenden, bevor die nächste gezeigt wird. Die Cascade-Schreibweise (..) von Dart ist hier praktisch:
ScaffoldMessenger.of(context)
..hideCurrentSnackBar()
..showSnackBar(const SnackBar(content: Text('Zum Warenkorb hinzugefügt')));Mit clearSnackBars() lassen sich alle wartenden Meldungen entfernen.
2. margin bei fixed-Verhalten setzen
Symptom: Die App bleibt mit der Assertion „Margin can only be used with floating behavior“ stehen.
Lösung: margin und width funktionieren nur zusammen mit behavior: SnackBarBehavior.floating. Entweder stellt man das Verhalten auf floating um oder entfernt diese Parameter. Beide gleichzeitig zu setzen ist ebenfalls ein Fehler; man entscheidet sich für einen.
3. Context nach einem await verwenden
Symptom: Der Analyzer meldet use_build_context_synchronously, und hat der Nutzer die Seite während der Anfrage verlassen, kommt es zur Laufzeit zu einem Fehler.
Lösung: Es gibt zwei Wege. Entweder nach dem await context.mounted prüfen oder den Messenger schon vor dem await in eine Variable holen:
Future<void> _save() async {
final messenger = ScaffoldMessenger.of(context);
await repository.save(profile);
messenger.showSnackBar(const SnackBar(content: Text('Gespeichert')));
}Der Vorteil des zweiten Wegs: Die Meldung kann auch dann noch erscheinen, wenn die Seite bereits geschlossen wurde.
4. SnackBar in initState anzeigen
Symptom: Der Fehler „dependOnInheritedWidgetOfExactType … was called before initState() completed“.
Ursache: Während initState läuft, ist das Widget noch nicht vollständig im Baum verankert, die Suche über ScaffoldMessenger.of(context) ist also nicht erlaubt. Die Reihenfolge dieser Phasen beschreibt der Beitrag zum Lebenszyklus.
Lösung: Auf die Zeit nach dem ersten Frame verschieben:
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Willkommen zurück')),
);
});
}Mini-Szenario: Löschen mit Rückgängig
Stellen wir uns eine Aufgabenliste vor. Löscht der Nutzer eine Aufgabe, fragen wir nicht nach, sondern entfernen sie sofort aus der Liste und bieten „Rückgängig“ an. Das eigentliche Löschen auf dem Server passiert erst, wenn die SnackBar verschwunden ist. Der Controller, den showSnackBar zurückgibt, besitzt das Feld closed – ein Future, das verrät, warum die SnackBar geschlossen wurde:
Future<void> _removeTask(int index) async {
final task = _tasks[index];
final messenger = ScaffoldMessenger.of(context);
setState(() => _tasks.removeAt(index));
messenger.hideCurrentSnackBar();
final controller = messenger.showSnackBar(
SnackBar(
content: Text('„${task.title}“ gelöscht'),
action: SnackBarAction(label: 'RÜCKGÄNGIG', onPressed: () {}),
),
);
final reason = await controller.closed;
if (reason == SnackBarClosedReason.action) {
if (!mounted) return;
setState(() => _tasks.insert(index, task)); // An die alte Stelle zurück
} else {
await widget.repository.delete(task.id); // Zeit abgelaufen, weggewischt usw.
}
}onPressed bleibt leer, weil uns SnackBarClosedReason.action bereits sagt, dass der Button gedrückt wurde. Kommt ein weiteres Löschen hinzu, schließt hideCurrentSnackBar() die vorherige SnackBar, und jene Aufgabe wird endgültig gelöscht. Rückgängig machen lässt sich also immer nur das letzte Löschen, und index bleibt gültig. Ein Vorbehalt: Wird die App in diesen wenigen Sekunden beendet, erreicht die Löschanfrage den Server nie. Bei kritischen Daten ist es sicherer, zuerst wirklich zu löschen und den Datensatz bei „Rückgängig“ neu anzulegen.
Das Muster funktioniert auch problemlos, wenn die Liste einen FloatingActionButton hat; das Scaffold sorgt selbst dafür, dass sich beide nicht überlappen.
Häufig gestellte Fragen
Wie lange bleibt eine SnackBar sichtbar?
Standardmäßig 4 Sekunden. Über den Parameter duration lässt sich das ändern; bei Meldungen, die Lesezeit brauchen oder eine Aktion enthalten, lohnt sich etwas mehr Zeit.
Kann ich eine SnackBar ohne Context anzeigen?
Ja. Legen Sie einen GlobalKey<ScaffoldMessengerState> an und übergeben Sie ihn dem Parameter scaffoldMessengerKey der MaterialApp. Danach können Sie von überall key.currentState?.showSnackBar(...) aufrufen.
Was ist der Unterschied zwischen SnackBar und Toast?
Flutter hat kein eingebautes Toast-Widget; das Material-Gegenstück ist die SnackBar. Sie wird im Widget-Baum der eigenen App gezeichnet, kann einen Aktionsbutton tragen und folgt dem Theme. Für einen Toast im Android-Stil ist ein zusätzliches Paket nötig.
Können mehrere SnackBars gleichzeitig sichtbar sein?
Nein, es ist immer nur eine sichtbar, die übrigen warten in der Warteschlange. Soll die neue Meldung sofort erscheinen, rufen Sie vorher hideCurrentSnackBar() auf.
Verwandte Artikel
Flutter: BottomSheet und showModalBottomSheet
showModalBottomSheet in Flutter: Werte zurückgeben, isScrollControlled, useSafeArea, showDragHandle, Tastatur, DraggableScrollableSheet und persistente Sheets.
Flutter: PopupMenuButton verwenden und Menüstrukturen
PopupMenuButton in Flutter für Drei-Punkte-Menüs: typsichere Enums, onSelected oder onTap, ein Listen-Szenario und typische Fehler.
Flutter: Card-Widget und Einsatz im Design
Card in Flutter: Material-3-Varianten Card.filled und Card.outlined, clipBehavior bei Bildern, antippbare Karten mit InkWell und typische Fehler.