Flutter: Innenabstände mit Padding steuern
Zuletzt aktualisiert:
6 Min. Lesezeit

Padding ist ein Widget mit genau einer Aufgabe: Es lässt Platz rund um sein Kind frei. Dazu zieht es die EdgeInsets von den erhaltenen Constraints ab, layoutet das Kind im verbleibenden Raum und verschiebt es um den angegebenen Betrag nach innen. Dass Karteninhalte nicht am Rand kleben, eine Listenzeile Luft bekommt oder eine Seite 16 Pixel vom Bildschirmrand entfernt bleibt, ist alles die Arbeit dieses Widgets. In diesem Beitrag zeige ich alle EdgeInsets-Konstruktoren, EdgeInsetsDirectional für Sprachen von rechts nach links, das Zusammenspiel mit SafeArea und Tastatur-Insets sowie die Fehler, die Ihnen in der Konsole am häufigsten begegnen.
Grundlegende Verwendung
Padding(
padding: const EdgeInsets.all(16),
child: Text('Um mich herum sind 16 Pixel Abstand'),
)Wie die offizielle API-Dokumentation des Padding-Widgets betont, ist Padding selbst unsichtbar; es hat keine Hintergrundfarbe und fügt keine Tap-Fläche hinzu. Es verkleinert nur den Raum für sein Kind und verschiebt es. Wenn Sie sich fragen, wo der Abstand geblieben ist, ist der schnellste Weg, das Padding im Flutter Inspector auszuwählen und die blau schraffierte Fläche anzusehen.
Die EdgeInsets-Konstruktoren
Abstandswerte werden mit der Klasse EdgeInsets angegeben. Es gibt vier Konstruktoren und eine Konstante; welchen Sie wählen, ist eine Frage der Lesbarkeit, das Ergebnis ist dasselbe.
// Alle vier Seiten gleich
const EdgeInsets.all(16)
// Horizontal (links+rechts) und vertikal (oben+unten) getrennt
const EdgeInsets.symmetric(horizontal: 16, vertical: 8)
// Nur die genannten Seiten; der Rest ist 0
const EdgeInsets.only(left: 16, top: 8)
// Links, oben, rechts, unten in dieser Reihenfolge (Left, Top, Right, Bottom)
const EdgeInsets.fromLTRB(16, 8, 16, 12)
// Gar kein Abstand
EdgeInsets.zeroWenn sich die Werte nie ändern, schreiben Sie const; dann legt der Widget-Baum nicht bei jedem Build ein neues EdgeInsets-Objekt an. fromLTRB reiht vier nackte Zahlen aneinander und ist am schwersten zu lesen; selbst wenn drei oder vier Seiten unterschiedlich sind, sind die benannten Parameter von only die bessere Wahl.
EdgeInsetsDirectional: Sprachen von rechts nach links
left und right sind physische Richtungen. Läuft Ihre App in einer Sprache, die von rechts nach links geschrieben wird (RTL), etwa Arabisch oder Hebräisch, bedeutet „16 Pixel am Textanfang" die rechte Kante, und left trifft die falsche Seite. Wie die API-Dokumentation zu EdgeInsetsDirectional beschreibt, arbeitet EdgeInsetsDirectional mit start und end und spiegelt sich anhand der umgebenden Directionality selbst:
Padding(
padding: const EdgeInsetsDirectional.only(start: 16, end: 8),
child: Text('In LTR 16 links, in RTL 16 rechts'),
)Auch EdgeInsetsDirectional.all, .symmetric und .fromSTEB (Start, Top, End, Bottom) stehen zur Verfügung. Wenn Ihre App nur in einer Links-nach-rechts-Sprache erscheint, reicht das physische EdgeInsets; in einer mehrsprachigen App erspart Ihnen die Directional-Variante überall dort, wo der horizontale Abstand asymmetrisch ist, ein späteres Umschreiben.
Padding, Container(padding) und SizedBox
Drei verschiedene Werkzeuge haben mit Abstand zu tun und werden gern verwechselt:
Padding: Abstand rund um ein einzelnes Kind. Die leichteste Option.Container(padding: ...): Steht ohnehin ein Container für Farbe, Rahmen oder abgerundete Ecken da, nutzen Sie dessen Parameterpadding. Container erzeugt daraus intern sowieso einPadding-Widget; ein zusätzlich eingepacktes Padding funktioniert, verschachtelt aber unnötig.SizedBox(height: 16): eine Lücke zwischen zwei Geschwister-Widgets. Um in einer Column Abstand zwischen zwei Texten zu schaffen, nehmen Sie SizedBox statt Padding; Padding umschließt ein Kind, es ist kein Trenner zwischen Geschwistern. Mehr dazu im Beitrag zu SizedBox.
Dann gibt es noch margin: Der Parameter margin des Container ist Außenabstand, die Hintergrundfarbe beginnt also erst nach der Lücke. padding ist Innenabstand, der Hintergrund deckt die Lücke mit ab. Ein farbiger Container zeigt den Unterschied am deutlichsten.
SafeArea und System-Insets
Notch, Statusleiste und die untere Navigationsleiste verdecken einen Teil des Bildschirms. SafeArea ist ein spezialisiertes Widget, das genau so viel Padding hinzufügt:
Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(children: [Text('Im sicheren Bereich')]),
),
),
)Wenn Sie selbst auslesen möchten, wie viel das System verdeckt, liefert MediaQuery.paddingOf(context) ein EdgeInsets; MediaQuery.paddingOf(context).bottom ist zum Beispiel die Höhe der unteren Navigationsleiste. Den von der Tastatur belegten Bereich lesen Sie über MediaQuery.viewInsetsOf(context).bottom. Meist übernimmt das Scaffold das über resizeToAvoidBottomInset für Sie; bauen Sie aber außerhalb eines Scaffold ein eigenes unteres Panel, müssen Sie diesen Wert zum Padding addieren. Wie Sie Bildschirmmaße mit MediaQuery auslesen, steht im Beitrag zu MediaQuery.
Wann verwenden – und wann nicht?
Greifen Sie zu Padding:
- Wenn der Inhalt eines einzelnen Widgets von dessen Rändern weg soll.
- Um den Seiteninhalt vom Bildschirmrand abzusetzen (
EdgeInsets.all(16)odersymmetric(horizontal: 16)). - Für den Innenabstand von Containern wie Karten, Listenzeilen und Dialogen.
Verwenden Sie Padding nicht:
- Für Abstand zwischen Geschwistern:
SizedBox(oder in aktuellen Flutter-Versionen der Parameterspacingvon Row und Column) ist sauberer. - Für den Randabstand einer ListView: nutzen Sie
ListView(padding: ...). Packen Sie die ListView von außen in ein Padding, schrumpft auch der Scrollbereich; Elemente werden an einer harten Linie abgeschnitten, statt unter den Rand zu gleiten. - Für Abstand innerhalb eines Buttons: Stilparameter wie
ElevatedButton.styleFrom(padding: ...)vergrößern die Tap-Fläche; ein außen herumgelegtes Padding tut das nicht. - Für negativen Abstand:
EdgeInsetslehnt negative Werte ab. Um ein Kind aus seiner Box hinauszuschieben, nehmen SieTransform.translateoderOverflowBox.
Häufige Fehler
1. Padding quetscht das Kind in einer engen Box
Symptom: Sie haben in einer Box mit fester Breite Padding ergänzt, und der Text bricht um oder das Icon schrumpft. Padding vergrößert nie seine eigene Größe; es zieht den Abstand vom Erhaltenen ab und reicht dem Kind den Rest. In einer 100 Pixel breiten SizedBox lässt EdgeInsets.all(20) dem Kind 60 Pixel.
// Das Kind bekommt 60 Pixel Breite
SizedBox(
width: 100,
child: Padding(
padding: const EdgeInsets.all(20),
child: Text('Ein langer Text bricht hier um'),
),
)Lösung: Die Box um den Padding-Betrag vergrößern oder das Padding außerhalb der Box platzieren.
2. Langen Text in einer Row mit Padding versehen
Symptom: A RenderFlex overflowed by 42 pixels on the right. Row gibt seinen Kindern unbegrenzte Breite; Padding reicht das an den Text weiter, der auf einer Zeile bleibt und überläuft.
Row(
children: [
const Icon(Icons.info),
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 8),
child: Text('Dieser Text bricht jetzt im Restplatz um'),
),
),
],
)Das Padding in ein Expanded zu setzen löst das Problem; warum Expanded dort nötig ist, erkläre ich im Beitrag zu Expanded.
3. Einen negativen Wert übergeben
Symptom: Die App stürzt im Debug-Modus mit der Assertion 'padding.isNonNegative': is not true ab. EdgeInsets darf nicht negativ sein; wenn Sie das Kind verschieben möchten, nehmen Sie Transform.translate(offset: Offset(-10, 0)).
4. Eine ListView in SafeArea einpacken
Symptom: Beim Scrollen gleiten die Elemente nicht natürlich unter die Statusleiste; oben bleibt eine harte Lücke. Ohne explizites padding wendet ListView die System-Insets entlang der Scrollachse bereits selbst an; ein außen herumgelegtes SafeArea verkleinert die Liste nur. Lösung: SafeArea entfernen und padding entweder weglassen oder einen eigenen Wert wie ListView(padding: MediaQuery.paddingOf(context)) übergeben. Die Elemente gleiten beim Scrollen unter die Notch, das erste Element beginnt trotzdem im sicheren Bereich.
Mini-Szenario: Login-Formular
Stellen Sie sich einen Anmeldebildschirm vor: Inhalt 24 Pixel vom Bildschirmrand entfernt, 16 Pixel zwischen den Feldern, und der Button darf beim Scrollen nicht an der Tastatur kleben.
class LoginScreen extends StatelessWidget {
const LoginScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 32),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text('Anmelden', style: Theme.of(context).textTheme.headlineMedium),
const SizedBox(height: 24),
const TextField(
decoration: InputDecoration(
labelText: 'E-Mail',
contentPadding: EdgeInsets.symmetric(horizontal: 16, vertical: 14),
border: OutlineInputBorder(),
),
),
const SizedBox(height: 16),
const TextField(
obscureText: true,
decoration: InputDecoration(
labelText: 'Passwort',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 24),
FilledButton(
style: FilledButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
),
onPressed: () {},
child: const Text('Anmelden'),
),
],
),
),
),
);
}
}Hier arbeiten drei Abstandswerkzeuge zusammen: SingleChildScrollView.padding legt die Seitenränder fest und gehört zum Scrollbereich; SizedBox liefert den Abstand zwischen den Feldern; contentPadding und FilledButton.styleFrom(padding:) sind der eigene Innenabstand der Komponenten und vergrößern ihre Tap-Fläche. SafeArea kümmert sich um die Notch, das Scaffold um die Tastatur. Die Validierungsseite dieses Formulars beschreibe ich im Beitrag zum Form-Widget.
Häufig gestellte Fragen
Was ist der Unterschied zwischen Padding und Margin?
Padding ist Innenabstand: Der Hintergrund des Widgets deckt die Lücke mit ab. Margin ist Außenabstand: Der Hintergrund beginnt erst nach der Lücke. Flutter hat kein eigenes Margin-Widget; der Parameter margin des Container ist in Wirklichkeit ein außen herumgelegtes Padding.
Ist padding im Container oder das Padding-Widget schneller?
Beide leisten dasselbe; erhält der Container ein padding, erzeugt er intern ein Padding-Widget. Wenn Sie nur Abstand brauchen, erzeugt Padding weniger Widgets; steht der Container ohnehin für Farbe oder Rahmen da, nutzen Sie dessen Parameter padding.
Warum akzeptiert EdgeInsets keine negativen Werte?
Padding reicht dem Kind den verbleibenden Raum weiter; ein negativer Wert hieße, dem Kind mehr Raum zu geben, als es selbst erhalten hat, was dem Layoutmodell widerspricht. Verwenden Sie Transform.translate, um ein Kind nach außen zu verschieben, und OverflowBox, um es überlaufen zu lassen.
Wie funktioniert Padding in Sprachen von rechts nach links korrekt?
Verwenden Sie die Parameter start/end von EdgeInsetsDirectional statt left/right. Das Widget wählt die Anfangskante automatisch anhand der nächsten Directionality; nur bei symmetrischem horizontalem Abstand macht es keinen Unterschied.
Verwandte Artikel
Flutter: Bildschirmabhängige Skalierung mit MediaQuery
Größen nach Bildschirm mit MediaQuery.sizeOf, paddingOf und textScalerOf; wann LayoutBuilder oder FractionallySizedBox besser passt und häufige Fehler.
Flutter: Widgets überlagern mit Stack und Positioned
Stack und Positioned in Flutter: wie ein Stack seine Größe bestimmt, fit, alignment, clipBehavior, Positioned.fill, PositionedDirectional, Badge und Overlays.
Flutter: BottomSheet und showModalBottomSheet
showModalBottomSheet in Flutter: Werte zurückgeben, isScrollControlled, useSafeArea, showDragHandle, Tastatur, DraggableScrollableSheet und persistente Sheets.