İçeriğe geç / Skip to content / Zum Inhalt

Flutter: Größen und Abstände mit SizedBox

Ahmet Balaman

Zuletzt aktualisiert:

6 Min. Lesezeit

FlutterSizedBoxLayoutSpacingConstraintsWidget
Flutter: Größen und Abstände mit SizedBox

SizedBox ist ein leichtgewichtiges Widget, das seinem Kind eine feste Breite und/oder Höhe aufzwingt oder, ohne Kind, einfach als leere Box in der angegebenen Größe dasteht. Die 16 Pixel zwischen zwei Texten, ein Button über die volle Breite, eine 40x40-Icon-Box, „nichts" anzeigen, wenn eine Bedingung nicht erfüllt ist: Das alles erledigt dieses Widget. In diesem Beitrag gehe ich die Konstruktoren durch, den Unterschied zu Container, den Grund, warum die gewünschte Größe manchmal ignoriert wird, und die häufigsten Fehler.

Grundlegende Verwendung

SizedBox(
  width: 200,
  height: 100,
  child: Container(
    color: Colors.blue,
    child: const Center(child: Text('200x100 Box')),
  ),
)

Sie können auch nur eine Achse angeben: SizedBox(width: 150, child: ElevatedButton(...)) fixiert die Breite des Buttons und überlässt die Höhe dem Button selbst. Auf der ausgelassenen Achse ist SizedBox durchlässig; das Kind wird dort mit der Constraint gemessen, die der Parent weitergibt.

Abstände erzeugen

Die häufigste Verwendung ist eine SizedBox ohne Kind als Trenner zwischen Geschwistern. In einer Column geben Sie height an, in einer Row width:

Column(
  children: [
    const Text('Erster Text'),
    const SizedBox(height: 16),
    const Text('Zweiter Text'),
    const SizedBox(height: 24),
    FilledButton(onPressed: () {}, child: const Text('Button')),
  ],
)

Abstandswerte sind konstant, also schreiben Sie const SizedBox(height: 16); dasselbe Objekt wird bei jedem Build wiederverwendet. Abstand ließe sich auch mit Padding erzeugen, aber Padding umschließt ein Kind, statt zwischen Geschwistern zu stehen; diese Unterscheidung erkläre ich im Beitrag zu Padding.

Benannte Konstruktoren

SizedBox bringt vier Hilfskonstruktoren mit:

  • SizedBox.expand(child:): füllt die maximale Breite und Höhe, die der Parent erlaubt. Es ist die Kurzform von width: double.infinity, height: double.infinity und scheitert, wenn der Parent auf einer Achse unbegrenzt ist.
  • SizedBox.shrink(): eine leere 0x0-Box. Der Standardweg, bedingt „nichts" zurückzugeben, und leichter als Container().
  • SizedBox.square(dimension: 40): eine quadratische Box; sie liest sich besser bei Avataren, Icon-Hintergründen, Ladeanzeigen und anderen gleichseitigen Elementen.
  • SizedBox.fromSize(size: Size(120, 40)): wenn Sie ohnehin ein Size-Objekt in der Hand haben.

SizedBox.expand füllt den Parent, shrink hat Größe null, square erzeugt ein Quadrat und fromSize nutzt ein vorhandenes Size-Objekt

// Ein Badge oder nichts, je nach Bedingung
unreadCount > 0 ? Badge(label: Text('$unreadCount')) : const SizedBox.shrink()

Innerhalb einer children-Liste ist ein Collection-if sauberer als der ternäre Operator: if (unreadCount > 0) Badge(...). shrink() ist für Stellen gedacht, an denen ein einzelner child-Parameter zwingend ein Widget erhalten muss.

Warum wird die angegebene Größe ignoriert?

Intern verhält sich SizedBox wie eine ConstrainedBox: Sie verrechnet die gewünschte Größe mit den Constraints des Parents, und die Constraints des Parents gewinnen immer. Dieses Modell, bei dem Constraints nach unten und Größen nach oben fließen, erklärt Flutters offizieller Leitfaden „Understanding constraints" Schritt für Schritt. Sagt der Parent „sei genau 360 Pixel breit" (eine tight Constraint), ist die Box 360 breit, auch wenn Sie width: 100 geschrieben haben.

Am häufigsten begegnet Ihnen das an drei Stellen:

// 1. Scaffold body: die SizedBox füllt den ganzen Bildschirm, nicht 100x100
Scaffold(body: SizedBox(width: 100, height: 100, child: ...))

// 2. In Expanded: die Breite ist, was Expanded weitergibt
Row(children: [Expanded(child: SizedBox(width: 100, child: ...))])

// 3. crossAxisAlignment: stretch: die Breite wird zur Breite der Column
Column(crossAxisAlignment: CrossAxisAlignment.stretch, children: [SizedBox(width: 100, ...)])

Die Lösung ist jedes Mal dieselbe: Setzen Sie die SizedBox in ein Widget, das die tight Constraint lockert. Center, Align und UnconstrainedBox sagen ihrem Kind „du darfst so klein sein, wie du willst", und dann greift die Größe der SizedBox. Flutters Regel „Constraints gehen nach unten, Größen nach oben" erkläre ich in der Einführung zu Widget-Baum und Layout.

SizedBox und Container

Auch Container nimmt width und height, aber Container ist ein Alleskönner: Je nach übergebenen Parametern erzeugt er intern Padding, DecoratedBox, ConstrainedBox und Align. Wenn Sie nur eine Größe wollen, erzeugt SizedBox weniger Widgets und macht die Absicht klarer. Brauchen Sie Farbe, Rahmen, Schatten oder abgerundete Ecken, nehmen Sie Container (oder direkt DecoratedBox). Ein leerer Container wächst auf die Größe eines begrenzten Parents; eine leere SizedBox bleibt bei der angegebenen Größe. Deshalb ist für Lücken SizedBox das richtige Werkzeug, nicht Container.

Wann verwenden – und wann nicht?

Verwenden Sie SizedBox:

  • Für eine feste Lücke zwischen Geschwistern (const SizedBox(height: 16)).
  • Um einem Kind eine feste Größe zu geben (Button über die volle Breite, 48 Pixel Zeilenhöhe).
  • Um bedingt nichts anzuzeigen (SizedBox.shrink()).

Wechseln Sie zu einem anderen Werkzeug:

  • Um den Restplatz zu füllen, nehmen Sie Expanded statt SizedBox.expand; Expanded ist das Widget, das in Row und Column funktioniert. Den Unterschied erkläre ich im Beitrag zu Expanded.
  • Für flexiblen Abstand („schiebe diese beiden an die gegenüberliegenden Enden") Spacer oder mainAxisAlignment: spaceBetween.
  • Um eine Größe in einem Bereich zu halten (mindestens 48, höchstens 200) ConstrainedBox.
  • Für viele gleiche Lücken bieten aktuelle Flutter-Versionen den Parameter spacing an Row und Column; eine Zeile statt zehn SizedBox(height: 8)-Einträge.

Häufige Fehler

1. height in einer Row, width in einer Column

Symptom: Die Lücke ist überhaupt nicht zu sehen. SizedBox(height: 16) hat entlang der Hauptachse einer Row die Breite null; horizontal trennt sie nichts. Verwenden Sie width in einer Row und height in einer Column.

2. double.infinity als Breite in einer Row

Symptom: BoxConstraints forces an infinite width. Row gibt seinen Kindern unbegrenzte Breite; SizedBox(width: double.infinity) versucht, diese Unendlichkeit anzunehmen, und das Layout bricht.

// Falsch
Row(children: [SizedBox(width: double.infinity, child: Text('x'))])

// Richtig: Expanded nimmt den Restplatz
Row(children: [Expanded(child: Text('x'))])

double.infinity ist nur dort sinnvoll, wo der Parent auf dieser Achse begrenzt ist (ein Scaffold body, die horizontale Achse einer Column).

3. Die ignorierte Größe für einen Flutter-Bug halten

Symptom: Sie haben SizedBox(width: 100) geschrieben und eine bildschirmbreite Box bekommen. Wie oben erklärt, hat die tight Constraint des Parents gewonnen. Packen Sie die Box in Center oder Align:

Scaffold(
  body: Center(
    child: SizedBox(width: 100, height: 100, child: ColoredBox(color: Colors.blue)),
  ),
)

4. Ein leerer Container statt shrink()

Symptom: Etwas, das unsichtbar sein sollte, belegt unerwartet Platz. Ein leerer Container() wächst auf die Größe eines begrenzten Parents. const SizedBox.shrink() ist immer 0x0.

Mini-Szenario: Profilkopf

Stellen Sie sich den Profilblock oben auf einem Einstellungsbildschirm vor: ein Avatar in fester Größe, Name und E-Mail, ein bedingtes „verifiziert"-Zeichen und ein Bearbeiten-Button über die volle Breite.

class ProfileHeader extends StatelessWidget {
  const ProfileHeader({super.key, required this.name, required this.email, required this.verified});

  final String name;
  final String email;
  final bool verified;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          Row(
            children: [
              SizedBox.square(
                dimension: 56,
                child: CircleAvatar(child: Text(name.substring(0, 1))),
              ),
              const SizedBox(width: 16),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(name, style: Theme.of(context).textTheme.titleMedium),
                    const SizedBox(height: 4),
                    Text(email, overflow: TextOverflow.ellipsis),
                  ],
                ),
              ),
              const SizedBox(width: 8),
              verified
                  ? const Icon(Icons.verified, color: Colors.green)
                  : const SizedBox.shrink(),
            ],
          ),
          const SizedBox(height: 16),
          SizedBox(
            height: 48,
            child: OutlinedButton(onPressed: () {}, child: const Text('Profil bearbeiten')),
          ),
        ],
      ),
    );
  }
}

SizedBox.square fixiert den Avatar auf 56x56; SizedBox(width: 16) und height: 4 sind Trenner; Expanded lässt den Textblock die restliche Breite einnehmen und kürzt eine lange E-Mail-Adresse. Die SizedBox des Buttons bekommt nur eine height: Die Breite kommt aus crossAxisAlignment: stretch der Column, width: double.infinity ist also nicht nötig. Für das Verifiziert-Zeichen habe ich SizedBox.shrink() verwendet; if (verified) const Icon(...) in der children-Liste der Row täte dasselbe.

Häufig gestellte Fragen

Was ist der Unterschied zwischen SizedBox und Container?

SizedBox legt nur eine Größe fest; Container erzeugt intern zusätzliche Widgets für Farbe, Padding, Rahmen und Ausrichtung. Wenn Sie nur eine Größe oder eine Lücke brauchen, ist SizedBox leichter und macht die Absicht klarer.

Warum wird die Breite meiner SizedBox nicht angewendet?

Die Constraint des Parents hat Vorrang vor dem Wunsch der SizedBox. An Stellen mit tight Constraints wie einem Scaffold body, Expanded oder CrossAxisAlignment.stretch wird die Box so groß wie der Parent; packen Sie die SizedBox in Center oder Align, um die Constraint zu lockern.

Sind SizedBox.shrink() und ein leerer Container() dasselbe?

Nein. SizedBox.shrink() ist immer 0x0; ein leerer Container() füllt einen begrenzten Parent vollständig aus. Verwenden Sie shrink, um bedingt nichts anzuzeigen, oder schreiben Sie in Listen ein Collection-if.

Tun SizedBox.expand und Expanded dasselbe?

Nein. SizedBox.expand füllt den maximalen Platz, den der Parent anbietet, und funktioniert auch außerhalb von Row und Column; Expanded verteilt nur den von Geschwistern übrig gelassenen Platz innerhalb von Row, Column und Flex. In einer Row wirft SizedBox.expand einen Fehler wegen unendlicher Breite.

Kommentare