Home
Flutter
Flutter Fundamentals: Layout
August 13, 2026
1 min

Table Of Contents

01
1. Row
02
2. Column
03
3. Expanded
04
4. Flexible
05
5. Stack
06
6. ListView
07
7. GridView
08
8. Constraints

Layout widgets arrange children on screen. Flutter does not use CSS. Parents pass constraints down, children return a size, then the parent positions them.

1. Row

Places children horizontally.

Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: const [
Icon(Icons.home),
Text("Home"),
Icon(Icons.search),
],
)
  • mainAxisAlignment → along the row (left to right)
  • crossAxisAlignment → across the row (top to bottom)
  • mainAxisSizemax fills width, min shrinks to children

2. Column

Places children vertically. Same alignment API as Row, with axes swapped.

Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: const [
Text("Title"),
Text("Subtitle"),
ElevatedButton(
onPressed: null,
child: Text("Go"),
),
],
)

A Column inside a vertical scroll view or unbounded height can overflow. Wrap it in Expanded, Flexible, or ListView when the parent does not give a max height.

3. Expanded

Takes the remaining space along the parent’s main axis. flex is how that space is split.

Row(
children: const [
Icon(Icons.star),
Expanded(
child: Text("This text takes the rest of the row"),
),
Icon(Icons.more_vert),
],
)
Row(
children: const [
Expanded(flex: 1, child: ColoredBox(color: Colors.red)),
Expanded(flex: 2, child: ColoredBox(color: Colors.blue)),
],
)

Expanded is Flexible with fit: FlexFit.tight. The child must fill the space it is given.

4. Flexible

Also shares leftover space, but the child can be smaller than the space (FlexFit.loose).

Row(
children: const [
Flexible(
child: Text("Short"),
),
Flexible(
child: Text("This long label can wrap instead of overflowing"),
),
],
)

Use Expanded when the child should fill. Use Flexible when the child may stay smaller.

5. Stack

Places children on top of each other. Size comes from non-positioned children (or fit).

Stack(
children: [
Image.network("https://picsum.photos/400/200"),
const Positioned(
left: 16,
bottom: 16,
child: Text("Caption"),
),
const Align(
alignment: Alignment.topRight,
child: Icon(Icons.favorite),
),
],
)
  • Children without Positioned / Align sit at the top-left by default (alignment)
  • Positioned pins a child to edges
  • Later children paint on top

6. ListView

A scrollable list. Prefer this over Column when the list can grow.

ListView(
children: const [
ListTile(title: Text("One")),
ListTile(title: Text("Two")),
ListTile(title: Text("Three")),
],
)

Build items lazily when the list is long:

ListView.builder(
itemCount: 20,
itemBuilder: (context, index) {
return ListTile(title: Text("Item $index"));
},
)
  • ListView scrolls and gives children a bounded constraint on the scroll axis
  • ListView.separated adds a divider between items
  • Nested in a Column? Wrap the ListView in Expanded

7. GridView

A scrollable grid.

GridView.count(
crossAxisCount: 2,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
children: const [
ColoredBox(color: Colors.red),
ColoredBox(color: Colors.green),
ColoredBox(color: Colors.blue),
ColoredBox(color: Colors.orange),
],
)

Lazy version:

GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 1,
),
itemCount: 20,
itemBuilder: (context, index) {
return ColoredBox(color: Colors.primaries[index % Colors.primaries.length]);
},
)

8. Constraints

Flutter layout is constraints go down, sizes go up, parent sets position.

A constraint is a min/max width and min/max height:

BoxConstraints(
minWidth: 0,
maxWidth: 300,
minHeight: 0,
maxHeight: 200,
)

What that means in practice:

  • Row / Column pass unbounded space on the main axis to children. A child that tries to be infinite (ListView, another Column with Expanded) overflows
  • Expanded / Flexible turn leftover space into a tight (or loose) constraint
  • Center / Align loosen constraints so the child can be smaller
  • SizedBox(width: 100, height: 100) gives a tight size
  • Container with no size tries to be as big as the parent, unless it has a child

Debug overflow (RIGHT OVERFLOWED BY 42 PIXELS) by asking: did the parent give a max width? If not, wrap with Expanded, Flexible, or give a width.


Tags

#Flutter

Share

Related Posts

Dart
Dart Basics: Top Concepts
August 13, 2026
1 min
© 2026, All Rights Reserved.
Powered By

Social Media

githublinkedinyoutube