Flutter: Platz und Ausrichtung mit mainAxisSize steuern
Zuletzt aktualisiert:
12 Min. Lesezeit

mainAxisSize ist der Parameter, der festlegt, wie viel Platz eine Row oder Column entlang ihrer Hauptachse belegt: bei der Row horizontal, bei der Column vertikal. Wenn eine Hintergrundfarbe plötzlich über die ganze Bildschirmbreite läuft, ein Dialog viel höher wird als sein Inhalt oder mainAxisAlignment.center scheinbar gar nichts bewirkt, liegt es meist an dieser einen Zeile. In diesem Beitrag geht es darum, was die beiden Werte genau tun, wie sie mit den Constraints des Eltern-Widgets und mit den Ausrichtungseinstellungen zusammenspielen und wo die Zeile in Dialogen, Bottom Sheets und Button-Gruppen hingehört.
Live-Demo: Beispiele zu mainAxisSize
Achten Sie im folgenden Beispiel auf die Hintergrundfarbe der Row, dann sehen Sie den Unterschied zwischen MainAxisSize.max und MainAxisSize.min:
💡 Falls das Beispiel oben nicht lädt, klicken Sie auf DartPad, um es in einem neuen Tab auszuführen.
Die beiden Werte: max und min
MainAxisSize.max (Standard)
Wenn Sie nichts angeben, arbeiten Row und Column mit max: Sie dehnen sich so weit aus, wie das Eltern-Widget es erlaubt, und platzieren ihre Kinder innerhalb dieser Fläche.
Row(
mainAxisSize: MainAxisSize.max, // Standard, auch ohne Angabe
children: const [
Icon(Icons.star),
Text('Maximale Breite'),
Icon(Icons.star),
],
)Selbst wenn die Kinder zusammen nur 150 Pixel brauchen, ist die Row so breit wie der Bildschirm. Die Differenz ist freier Platz, und genau den verteilt mainAxisAlignment.
MainAxisSize.min
Mit min ist die Row oder Column genau so groß wie die Summe ihrer Kinder und nimmt nichts darüber hinaus:
Row(
mainAxisSize: MainAxisSize.min,
children: const [
Icon(Icons.star),
Text('Minimale Breite'),
Icon(Icons.star),
],
)Bei einer Column gilt dieselbe Logik auf der vertikalen Achse: Mit min ist sie nur so hoch wie ihr Inhalt. Ein Detail ist dabei wichtig: Der Parameter wirkt ausschließlich auf die Hauptachse. Die Breite einer Column beziehungsweise die Höhe einer Row ergibt sich ohnehin aus dem größten Kind.
| Eigenschaft | MainAxisSize.max | MainAxisSize.min |
|---|---|---|
| Größe auf der Hauptachse | So viel, wie das Eltern-Widget erlaubt | Summe der Kinder |
| Standard | Ja | Nein |
| Freier Platz | Vorhanden, wird von mainAxisAlignment verteilt |
Keiner, es gibt nichts zu verteilen |
| Typischer Einsatz | Bildschirmgerüst, Toolbar-Zeile | Badge, Dialoginhalt, Button-Gruppe |
Constraints haben immer das letzte Wort
In Flutter wählt ein Widget seine Größe nicht allein. Das Eltern-Widget schickt Constraints, das Kind sucht sich innerhalb dieses Bereichs eine Größe aus. mainAxisSize arbeitet innerhalb dieser Regel, und in zwei Situationen verhält es sich anders als erwartet:
- Bei engen (tight) Constraints bleibt
minwirkungslos. Ein Kind einer ListView, ein Kind einer Column mitcrossAxisAlignment: CrossAxisAlignment.stretchoder eine Row inSizedBox(width: double.infinity)bekommt die Anweisung „sei genau so breit“ und ist es dann auch, egal was Sie schreiben. - Bei unbegrenzten (unbounded) Constraints verhält sich
maxwiemin. Einer Column in einemSingleChildScrollViewwird unendliche Höhe angeboten; Unendlich lässt sich nicht ausfüllen, also wird sie so hoch wie ihr Inhalt.
Wenn Sie zuerst sehen möchten, wo Row und Column im Widget-Baum stehen, ist der Beitrag zu Widget-Baum, Row, Column und Stack ein guter Einstieg.
mainAxisSize und Ausrichtung: Eine Row legt in drei Schritten an
mainAxisSize, mainAxisAlignment und crossAxisAlignment wirken wie drei unabhängige Einstellungen, aber die Ausrichtung arbeitet mit dem freien Platz, den die Größeneinstellung übrig lässt. Wenn eine Row (oder Column) ihre Kinder platziert, macht sie der Reihe nach drei Dinge:
- Sie misst die nicht flexiblen Kinder und verteilt den Restplatz an
Expanded- undFlexible-Kinder. - Sie legt anhand von
mainAxisSizeihre eigene Größe auf der Hauptachse fest: beimaxdie größte vom Eltern-Widget erlaubte Größe, beimindie Summe der Kinder. - Sie verteilt die Differenz zwischen ihrer eigenen Größe und der Summe der Kinder, also den freien Platz, nach der Regel von
mainAxisAlignment.
Der dritte Schritt erklärt alles. Wählen Sie min, ist die Row bereits genau so groß wie ihre Kinder, der freie Platz ist null; center, end, spaceBetween oder spaceEvenly haben kein sichtbares Ergebnis. Der Code läuft fehlerfrei, es gibt nur nichts auszurichten.
// Diese beiden Rows sehen gleich aus: mit min gibt es keinen freien Platz, center bewirkt nichts.
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: const [Icon(Icons.star), Text('Favorit')],
)
Row(
mainAxisSize: MainAxisSize.min,
children: const [Icon(Icons.star), Text('Favorit')],
)| Kombination | Ergebnis |
|---|---|
max + start |
Kinder links, freier Platz rechts (Standard) |
max + center |
Kinder in der Mitte, freier Platz auf beiden Seiten |
max + spaceBetween |
Freier Platz wird zwischen den Kindern verteilt |
min + beliebiger Wert |
Kein freier Platz, Ausrichtung unsichtbar |
min + Expanded oder Spacer im Inneren |
Das flexible Kind fordert allen Platz, die Row verhält sich wie max |
Zwei Wege, eine Gruppe zu zentrieren
Wer „zentriere die Row“ sagt, kann zwei verschiedene Dinge meinen, und der Code unterscheidet sich.
Soll die Row selbst in voller Breite bleiben und nur ihre Kinder in der Mitte sitzen, nehmen Sie max mit mainAxisAlignment.center. Geben Sie der Row einen Hintergrund, spannt sich dieser über die ganze Zeile.
Soll die Row als Ganzes nur so breit sein wie ihr Inhalt und dieses Ganze in der Mitte stehen, geben Sie der Row min und überlassen die Positionierung dem übergeordneten Widget:
Center(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
color: Colors.amber,
child: Row(
mainAxisSize: MainAxisSize.min,
children: const [Icon(Icons.star), SizedBox(width: 4), Text('Favorit')],
),
),
)Hier umschließt der Hintergrund nur Icon und Text. Für eine rechtsbündige Platzierung ersetzt Align(alignment: Alignment.centerRight, ...) das Center; die weiteren Optionen stehen im Beitrag zum Align-Widget. Kurz gesagt gilt: Die Position einer Row mit min bestimmt das Widget, das sie umschließt, nicht die Row selbst.
crossAxisAlignment arbeitet auf einer eigenen Achse
crossAxisAlignment steuert in einer Row die vertikale und in einer Column die horizontale Ausrichtung und wird von mainAxisSize nicht beeinflusst. Die Höhe einer Row entspricht immer ihrem höchsten Kind; die übrigen Kinder werden innerhalb dieser Höhe mit start, center, end oder baseline ausgerichtet. Weil der Standard center ist, zentrieren sich ein Icon und ein Text unterschiedlicher Größe von selbst.
Die einzige Ausnahme ist stretch: Es zwingt die Kinder auf der Querachse auf die größtmögliche Größe. Dafür muss die Querachse begrenzt sein; was passiert, wenn sie es nicht ist, zeigt der Abschnitt zu den Fehlern.
Noch ein Detail zur Richtung: start und end folgen der Textrichtung. In Sprachen mit Schreibrichtung von rechts nach links wie Arabisch bedeutet MainAxisAlignment.start in einer Row die rechte Seite; brauchen Sie zwingend linksbündig, geben Sie der Row textDirection: TextDirection.ltr.
Rezepte: Dialog, Button-Gruppe und Bottom Sheet
Am meisten bringt min bei kleinen Bausteinen, deren Höhe oder Breite aus dem Inhalt kommen muss.
Dialoginhalt
Legen Sie eine Column in einen AlertDialog und starten die App, nimmt der Dialog fast den gesamten Bildschirm ein. Ein Dialog bietet seinem Inhalt eine Obergrenze nahe der Bildschirmhöhe; eine Column mit max nimmt diese Grenze vollständig ein, eine Column mit min nur so viel, wie Icon und Text brauchen:
Future<bool?> showDeleteDialog(BuildContext context) {
return showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: const Text('Notiz löschen'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: const [
Icon(Icons.warning_amber_rounded, size: 48, color: Colors.orange),
SizedBox(height: 16),
Text('Diese Notiz wird dauerhaft gelöscht.'),
],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: const Text('Abbrechen'),
),
FilledButton(
onPressed: () => Navigator.pop(context, true),
child: const Text('Löschen'),
),
],
),
);
}Besteht der Inhalt aus einem einzigen Text, brauchen Sie gar keine Column; schreiben Sie direkt content: Text(...). Bauen Sie für die unteren Buttons auch keine eigene Row, sondern nutzen Sie den Parameter actions: Passen die Buttons nicht nebeneinander, stapelt er sie selbst untereinander, eine handgeschriebene Row läuft über. Die übrigen Parameter des Dialogs finden Sie im Beitrag zur Verwendung von AlertDialog.
Button-Gruppe mit Rahmen
Bei kleinen Gruppen wie einem Mengenwähler oder Like-/Teilen-Icons ist min Pflicht, sobald die Row einen Rahmen oder Hintergrund hat. Sonst zieht sich der Rahmen über die ganze Zeile:
class QuantityStepper extends StatelessWidget {
const QuantityStepper({
super.key,
required this.value,
required this.onChanged,
});
final int value;
final ValueChanged<int> onChanged;
@override
Widget build(BuildContext context) {
return DecoratedBox(
decoration: BoxDecoration(
border: Border.all(color: Theme.of(context).colorScheme.outline),
borderRadius: BorderRadius.circular(12),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
onPressed: value > 1 ? () => onChanged(value - 1) : null,
icon: const Icon(Icons.remove),
),
Text('$value'),
IconButton(
onPressed: () => onChanged(value + 1),
icon: const Icon(Icons.add),
),
],
),
);
}
}Weil die Gruppe nur so breit ist wie ihr Inhalt, lässt sie sich als Ganzes leicht verschieben: mit Center zentrieren, mit Align nach rechts setzen. Die Position über das mainAxisAlignment der Row selbst zu steuern, funktioniert aus dem oben beschriebenen Grund nicht.
Bottom Sheet
Stellen Sie sich eine Produktseite vor, auf der ein Tipp auf „In den Warenkorb“ ein kleines Panel von unten öffnet: Produktname, Mengenwähler und ein Bestätigen-Button in voller Breite. Der QuantityStepper von oben kommt hier zum Einsatz:
void showAddToCartSheet(BuildContext context) {
var quantity = 1;
showModalBottomSheet<void>(
context: context,
showDragHandle: true,
builder: (context) {
return StatefulBuilder(
builder: (context, setSheetState) {
return SafeArea(
child: Padding(
padding: const EdgeInsets.fromLTRB(24, 0, 24, 24),
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
'Filterkaffee 250 g',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 16),
Center(
child: QuantityStepper(
value: quantity,
onChanged: (v) => setSheetState(() => quantity = v),
),
),
const SizedBox(height: 16),
FilledButton(
onPressed: () => Navigator.pop(context),
child: const Text('In den Warenkorb'),
),
],
),
),
);
},
);
},
);
}Zwei getrennte min erledigen hier zwei getrennte Aufgaben. Das min der Column sorgt dafür, dass das Sheet nur so hoch wird wie seine drei Zeilen Inhalt; ohne dieses min würde das Panel auf die größte erlaubte Höhe wachsen. Das min der Row legt den Rahmen des Mengenwählers eng um den Inhalt. Weil die Column stretch ist, hat der Button die volle Breite; der Mengenwähler entzieht sich dem Zwang durch Center und bleibt kompakt in der Mitte. Enthält das Sheet eine Liste, die den ganzen Bildschirm füllen könnte, reicht min nicht; nehmen Sie isScrollControlled: true mit einem scrollbaren Körper.
Wann verwenden – und wann nicht?
Greifen Sie zu min, wenn ein Container, eine Card oder eine DecoratedBox um die Row oder Column herum eng am Inhalt anliegen soll, wenn Sie die Gruppe als Ganzes zentrieren oder rechts ausrichten möchten und überall dort, wo die Höhe aus dem Inhalt kommen muss, etwa in Dialogen und Bottom Sheets.
Bleiben Sie bei max, wenn Sie Kinder mit spaceBetween oder spaceEvenly über die Fläche verteilen, wenn Sie Elemente in einer Werkzeugleiste voller Breite zentrieren, wenn Sie innen Expanded oder Spacer einsetzen oder wenn Sie das Grundgerüst eines Bildschirms bauen. Der freie Platz ist hier Teil des Designs.
Für manche Aufgaben ist ein anderes Widget das richtige Werkzeug:
- Um ein einzelnes Kind in seiner eigenen Größe zu belassen und zu positionieren, brauchen Sie keine Row; Align oder
Centergenügt. - Für Tags und Chips, die bei Platzmangel in die nächste Zeile umbrechen sollen, nehmen Sie
Wrap;minverhindert keinen Overflow. - Für „Wähle eins“-Gruppen (Tag / Woche / Monat) liefert
SegmentedButtonden ausgewählten Zustand und Barrierefreiheit gleich mit. - Für flexiblen Abstand zwischen zwei Elementen kann
Spacerlesbarer sein alsspaceBetween; den Unterschied erklärt der Beitrag zu Spacer.
Häufige Fehler
1. min ist gesetzt, aber die Row ist weiterhin voll breit
Symptom: Der Hintergrund des Badges zieht sich trotz min über die ganze Zeile. Ursache ist der oben beschriebene enge Constraint: Das Eltern-Widget erzwingt die Breite. Es genügt schon, Kind einer ListView zu sein oder in einer Column mit stretch zu stehen. Die Lösung ist ein Widget dazwischen, das den Constraint lockert:
ListView(
children: [
Align(
alignment: Alignment.centerLeft,
child: Container(
color: Colors.amber,
child: Row(
mainAxisSize: MainAxisSize.min,
children: const [Icon(Icons.bolt), Text('Schnelle Lieferung')],
),
),
),
],
)2. Expanded oder Spacer in einer Row oder Column mit min
Symptom: Sie haben min geschrieben, die Row nimmt trotzdem die volle Breite, der Dialog dehnt sich trotzdem über die volle Höhe. Expanded und Spacer verlangen den gesamten restlichen Platz, und sobald ein Kind alles beansprucht, ist die Summe eben alles. Soll das Widget am Inhalt anliegen, entfernen Sie das flexible Kind oder verwenden Sie Flexible (dessen Standardwert für fit ist FlexFit.loose, das Kind darf also klein bleiben). In Dialogen und Sheets müssen Abstände fest sein: SizedBox(height: 16). Den Unterschied zwischen Expanded und Flexible erkläre ich ausführlich im Vergleich von Expanded, Flexible und Spacer.
3. Von min plus mainAxisAlignment.center eine Zentrierung erwarten
Symptom: Die Kinder der Row bleiben links, es erscheint kein Fehler. Der Grund ist der freie Platz von null. Entweder min entfernen und max mit center verwenden, oder min behalten und die Row in Center packen. Welche Variante Sie wählen, hängt davon ab, ob der Hintergrund die Zeile oder den Inhalt abdecken soll.
4. Glauben, dass min einen Overflow verhindert
Symptom: Auf kleinen Bildschirmen oder bei geöffneter Tastatur erscheint am unteren Rand des Dialogs ein gelb-schwarzer Streifen mit A RenderFlex overflowed by ... pixels on the bottom. min verkleinert keinen Inhalt, es verzichtet nur auf den leeren Platz. Kann der Inhalt wachsen, machen Sie ihn scrollbar:
AlertDialog(
scrollable: true,
title: const Text('Nutzungsbedingungen'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: const [
Text('Langer Text...'),
],
),
)5. Expanded in einem scrollbaren Bereich
SingleChildScrollView(
child: Column(
children: [
const Text('Titel'),
Expanded(child: Container(color: Colors.blue)), // Fehler
],
),
)Das Symptom ist diese Meldung in der Konsole: RenderFlex children have non-zero flex but incoming height constraints are unbounded. Bei unendlicher Höhe lässt sich kein „restlicher Platz“ berechnen. Die Fehlermeldung nennt die Lösung selbst: mainAxisSize: MainAxisSize.min zusammen mit FlexFit.loose bei den flexiblen Kindern verwenden oder Expanded durch eine feste Höhe ersetzen.
6. stretch an einer Row in einer Column
Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.stretch, // Fehler
children: [Container(color: Colors.blue, child: const Text('A'))],
),
],
)Symptom: BoxConstraints forces an infinite height. in der Konsole und ein leerer Bildschirm. Weil die Column vertikal keine Grenze setzt, werden die Kinder der Row ins Unendliche gezogen. Geben Sie der Row eine Höhe: SizedBox(height: 48, child: Row(...)). Reicht es, sich am höchsten Kind zu orientieren, funktioniert auch IntrinsicHeight; es ist aber teuer, deshalb in langen Listen vermeiden.
7. textBaseline bei baseline-Ausrichtung vergessen
Symptom: Sobald Sie crossAxisAlignment: CrossAxisAlignment.baseline schreiben, stoppt die App mit der Assertion textBaseline is required if you specify the crossAxisAlignment with CrossAxisAlignment.baseline. Wenn Sie zwei Texte unterschiedlicher Größe an der Grundlinie ausrichten, müssen Sie textBaseline: TextBaseline.alphabetic ergänzen.
Mini-Szenario 1: Status-Badge in einer Bestellliste
Stellen Sie sich eine Bestellliste vor, in der jede Zeile ein kleines Badge wie „Versendet“ oder „Zugestellt“ trägt. Das Badge ist ein farbiger Container um eine Row aus Icon und Text:
class StatusBadge extends StatelessWidget {
const StatusBadge({super.key, required this.label, required this.icon});
final String label;
final IconData icon;
@override
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
return Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(
color: scheme.secondaryContainer,
borderRadius: BorderRadius.circular(999),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 16, color: scheme.onSecondaryContainer),
const SizedBox(width: 6),
Text(label, style: TextStyle(color: scheme.onSecondaryContainer)),
],
),
);
}
}Ein Container übernimmt seine Größe vom Kind. Mit max würde sich der Container über die ganze Zeile ziehen, und aus dem Badge würde ein farbiger Streifen. Mit min liegt der Container eng an Icon und Text an. Setzen Sie das Badge in eine Column mit crossAxisAlignment: CrossAxisAlignment.start, steht es kompakt links; hätte dieselbe Column stretch, wären Sie wieder bei Fehler 1 und müssten das Badge in Align einpacken.
Mini-Szenario 2: Chat-Blase
Stellen Sie sich einen Nachrichtenbildschirm vor. Ihre eigenen Nachrichten stehen rechts, die des Gegenübers links; jede Blase ist so breit wie ihr Text, aber höchstens drei Viertel des Bildschirms. In der Blase stehen der Text und rechts unten eine kleine Uhrzeit:
class ChatBubble extends StatelessWidget {
const ChatBubble({
super.key,
required this.text,
required this.time,
required this.isMine,
});
final String text;
final String time;
final bool isMine;
@override
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
final maxWidth = MediaQuery.sizeOf(context).width * 0.75;
return Align(
alignment: isMine ? Alignment.centerRight : Alignment.centerLeft,
child: Container(
constraints: BoxConstraints(maxWidth: maxWidth),
margin: const EdgeInsets.symmetric(horizontal: 12, vertical: 4),
padding: const EdgeInsets.fromLTRB(12, 8, 8, 6),
decoration: BoxDecoration(
color: isMine ? scheme.primaryContainer : scheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(16),
),
child: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Flexible(child: Text(text)),
const SizedBox(width: 8),
Text(time, style: Theme.of(context).textTheme.labelSmall),
],
),
),
);
}
}Die drei Einstellungen erledigen hier drei getrennte Aufgaben. Das min der Row sorgt dafür, dass der Hintergrund der Blase nur Text und Uhrzeit umschließt; mit max wäre jede Blase drei Viertel breit. Ob die Blase rechts oder links steht, entscheidet das umgebende Align, nicht die Row; hätten Sie es mit mainAxisAlignment versucht, wäre wegen min nichts passiert. crossAxisAlignment: CrossAxisAlignment.end zieht die Uhrzeit bei einer mehrzeiligen Nachricht auf die letzte Zeile. Der Text steckt in Flexible, weil eine lange Nachricht an der Grenze der Blase umbrechen muss; mit Expanded würde der Text immer die volle Breite fordern, und min verlöre seine Wirkung.
Häufig gestellte Fragen
Was ist der Standardwert von mainAxisSize?
Für Row und Column ist der Standard MainAxisSize.max. Ohne Angabe dehnt sich das Widget entlang der Hauptachse so weit aus, wie das Eltern-Widget es erlaubt.
Warum funktioniert mainAxisAlignment.center nicht?
Sehr wahrscheinlich hat die Row oder Column mainAxisSize: MainAxisSize.min. Mit min bleibt kein freier Platz übrig, die Ausrichtung ist unsichtbar. Verwenden Sie entweder max oder packen Sie das Widget in Center.
Warum füllt mein AlertDialog den ganzen Bildschirm?
Die Column in content läuft mit dem Standardwert MainAxisSize.max und nimmt deshalb die gesamte Höhe, die der Dialog erlaubt. Mit mainAxisSize: MainAxisSize.min an der Column wird der Dialog so hoch wie sein Inhalt. Passt der Inhalt dann immer noch nicht, setzen Sie scrollable: true.
Behebt mainAxisSize.min Overflow-Fehler?
Nein. min verzichtet nur auf den freien Platz; brauchen die Kinder zusammen mehr als vorhanden ist, erscheint weiterhin „RenderFlex overflowed“. Gegen Overflow helfen Expanded, Flexible, Wrap oder ein scrollbares Widget.
Warum ist meine Row trotz min weiterhin voll breit?
Sehr wahrscheinlich schickt das Eltern-Widget enge Constraints (Kind einer ListView, Column mit stretch, SizedBox mit unendlicher Breite), oder in der Row steckt ein Expanded oder Spacer. Die Row in Align oder Center einzupacken oder das flexible Kind zu entfernen, löst das Problem.
Wirkt mainAxisSize auch auf die Querachse?
Nein, nur auf die Hauptachse. Eine Column ist so breit wie ihr breitestes Kind; um die Breite auszufüllen, verwenden Sie crossAxisAlignment: CrossAxisAlignment.stretch. Das setzt wiederum eine begrenzte Querachse voraus.
Verwandte Artikel
Flutter: Flexible Abstände mit dem Spacer-Widget
Was in Spacer steckt, Abstände mit flex gewichten, der Unterschied zu SizedBox und mainAxisAlignment und warum Spacer in scrollbaren Bereichen scheitert.
Flutter: Platz ausfüllen mit dem Expanded-Widget
Expanded im Detail: Wie der flex-Anteil berechnet wird, Verschachtelung, warum es nur in Row und Column funktioniert und die drei häufigsten Fehler.
Einführung in Flutter: Widget-Baum, Row, Column und Stack
Nach Dart bin ich endlich zu Flutter gewechselt. Am ersten Tag lerne ich den Widget-Baum sowie die Strukturen Row, Column und Stack.