Day 6: Layout Widgets – Rows, Columns & Stacks

flutter Layout Widgets – Rows, Columns & Stacks

Welcome to Day 6 of our Flutter adventure! So far, you’ve learned why Flutter is awesome, grasped the basics of Dart, and understood that “everything is a Widget.” Today is where things get really exciting: we’re going to learn how to arrange those widgets on the screen to build your app’s visual layout!

Interactive Flutter Layout Guide

Flutter Layout Playground

Explore how to arrange widgets with `Row`, `Column`, `Stack`, and more!

1. `Column`: Arranging Widgets Vertically

A `Column` widget arranges its children one below another. Use the controls below to see how you can position them along the main (vertical) and cross (horizontal) axes.

Item 1
Item 2
Item 3
Column(
  mainAxisAlignment: MainAxisAlignment.center, // Controlled by Main Axis Alignment
  crossAxisAlignment: CrossAxisAlignment.start, // Controlled by Cross Axis Alignment
  children: <Widget>[
    Text('Item 1'),
    Text('Item 2'),
    Text('Item 3'),
  ],
)

2. `Row`: Arranging Widgets Horizontally

A `Row` widget arranges its children side-by-side. Experiment with the controls to see how you can position them along the main (horizontal) and cross (vertical) axes.

Item 1
Item 2
Item 3
Row(
  mainAxisAlignment: MainAxisAlignment.center, // Controlled by Main Axis Alignment
  crossAxisAlignment: CrossAxisAlignment.center, // Controlled by Cross Axis Alignment
  children: <Widget>[
    Icon(Icons.thumb_up),
    Text('Like'),
    Icon(Icons.comment),
    Text('Comment'),
  ],
)

3. `Stack`: Layering Widgets

A `Stack` allows you to place widgets directly on top of each other. The first child is at the bottom, and subsequent children are layered on top. Use the buttons to change the position of the overlay item.

Base Layer (Image/Container)
Overlay Text
Stack(
  children: <Widget>[
    // This will be at the bottom
    Container(
      width: 200,
      height: 200,
      color: Colors.blue,
    ),
    // This will be on top of the blue container, positioned by Alignment
    Align( // Or Positioned widget for precise control
      alignment: Alignment.center, // Controlled by buttons
      child: Text(
        'Layered Text',
        style: TextStyle(color: Colors.white, fontSize: 24),
      ),
    ),
  ],
)

`Expanded` and `Flexible`: Giving Widgets Room

These widgets control how children fill available space within a `Row` or `Column`. `Expanded` forces its child to fill all remaining space, while `Flexible` allows it to fill space without forcing overflow.

Fixed
This text will expand or flex based on the setting.
Fixed
Row(
  children: <Widget>[
    Container(width: 50, height: 50, color: Colors.purple),
    Expanded( // Currently Expanded
      child: Text('This text will expand to fill the row!'),
    ),
    Container(width: 50, height: 50, color: Colors.purple),
  ],
)

You’ve mastered Flutter layouts! Next up: User Interaction on Day 7.

Think of it like arranging furniture in a room. You don’t just throw everything in; you put the sofa against one wall, the TV opposite it, and a lamp next to the armchair. In Flutter, we use special Layout Widgets to organize our other widgets.

The three most fundamental layout widgets are Row, Column, and Stack. Let’s dive in!

1. Column: Arranging Widgets Vertically (One Below Another)

Imagine you want to display a list of items, like a user’s profile picture, their name, and then their email, all neatly stacked one below the other. This is a perfect job for a Column widget.

A Column takes a list of children (other widgets) and arranges them vertically, from top to bottom.

Analogy: Think of a stack of books. Each book is a widget, and the Column is what holds them in a vertical pile.

Column(
  children: <Widget>[
    Text('Profile Picture'),
    Text('John Doe'),
    Text('john.doe@example.com'),
  ],
)

2. Row: Arranging Widgets Horizontally (Side-by-Side)

Now, what if you want to place items next to each other, like an icon followed by some text, or a button on the left and another on the right? For this, you use a Row widget.

A Row also takes a list of children and arranges them horizontally, from left to right.

Analogy: Imagine people standing in a line. Each person is a widget, and the Row keeps them standing side-by-side.

Row(
  children: <Widget>[
    Icon(Icons.star),
    Text('Rating: 4.5'),
  ],
)

MainAxisAlignment and CrossAxisAlignment: How to Position Widgets

Once you have a Row or Column, you’ll often want to control how its children are positioned within that row or column. This is where MainAxisAlignment and CrossAxisAlignment come in.

Every Row and Column has two axes:

  • Main Axis:
    • For a Column, the main axis is vertical (top to bottom).
    • For a Row, the main axis is horizontal (left to right).
    • MainAxisAlignment controls how children are placed along this main axis. Common values include:
      • start: Place children at the beginning (top for Column, left for Row).
      • end: Place children at the end (bottom for Column, right for Row).
      • center: Center children along the axis.
      • spaceBetween: Distribute space evenly between children.
      • spaceAround: Distribute space evenly around children (including before the first and after the last).
      • spaceEvenly: Distribute space evenly, including at the ends.
  • Cross Axis:
    • For a Column, the cross axis is horizontal (left to right).
    • For a Row, the cross axis is vertical (top to bottom).
    • CrossAxisAlignment controls how children are placed perpendicular to the main axis. Common values include:
      • start: Place children at the beginning of the cross axis.
      • end: Place children at the end of the cross axis.
      • center: Center children along the cross axis.
      • stretch: Make children fill the available space along the cross axis.

Example with Column:

Column(
  mainAxisAlignment: MainAxisAlignment.center, // Vertically center children
  crossAxisAlignment: CrossAxisAlignment.start, // Horizontally align children to the left
  children: <Widget>[
    Text('Hello'),
    Text('World!'),
  ],
)

Example with Row:

Row(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly, // Horizontally distribute children evenly
  crossAxisAlignment: CrossAxisAlignment.center,    // Vertically center children
  children: <Widget>[
    Icon(Icons.thumb_up),
    Text('Like'),
    Icon(Icons.comment),
    Text('Comment'),
  ],
)

3. Stack: Layering Widgets (One on Top of Another)

Sometimes, you need to place widgets directly on top of each other, like putting text over an image, or a badge icon on a profile picture. This is where the Stack widget comes in.

A Stack allows you to layer multiple children widgets on top of each other, like a stack of papers. The first child in the list is at the bottom of the stack, and the last child is at the top.

Analogy: Think of transparent sheets of paper. You draw something on each sheet and then stack them up. Everything drawn on the top sheet is visible, and you can see through it to the sheets below.

Stack(
  children: <Widget>[
    // This will be at the bottom
    Container(
      width: 200,
      height: 200,
      color: Colors.blue,
    ),
    // This will be on top of the blue container, centered
    Center(
      child: Text(
        'Layered Text',
        style: TextStyle(color: Colors.white, fontSize: 24),
      ),
    ),
  ],
)

Expanded and Flexible: Giving Widgets Room to Grow (or Shrink)

What happens if you put a Text widget in a Row and it’s too long? Or if you want one part of your Row to take up more space than others? That’s where Expanded and Flexible are useful.

These widgets are used as children inside Row or Column to control how much space their child takes up along the main axis.

  • Expanded:
    • Forces its child to fill all available space along the Row‘s or Column‘s main axis.
    • If multiple Expanded widgets are present, they share the available space. You can give them a flex property (e.g., flex: 2) to make one take twice as much space as another.
    Row( children: <Widget>[ Container(width: 50, height: 50, color: Colors.red), Expanded( // This text will take up all remaining space child: Text('This text is very long and will expand to fill the row!'), ), Container(width: 50, height: 50, color: Colors.blue), ], )
  • Flexible:
    • Allows its child to fill available space, but it’s “flexible” and won’t force its child to take up all the space if the child doesn’t need it.
    • Useful when you want a widget to expand if there’s room, but also shrink if there isn’t enough space, without causing overflow.
    Row( children: <Widget>[ Container(width: 100, height: 50, color: Colors.red), Flexible( // This text will take available space, but won't force overflow child: Text('This text is flexible and will wrap or shrink if needed.'), ), Container(width: 100, height: 50, color: Colors.green), ], )

Conclusion

Today, you’ve unlocked the power of Flutter’s layout system! You now understand how to use Row to arrange widgets horizontally, Column for vertical arrangements, and Stack for layering. You’ve also learned how MainAxisAlignment, CrossAxisAlignment, Expanded, and Flexible give you precise control over how your widgets are positioned.

These layout widgets are the backbone of every Flutter UI. Practice combining them, and you’ll soon be building complex and beautiful screens with ease.

Tomorrow, on Day 7, we’ll explore User Interaction – how to add buttons, handle taps, and get input from users to make your apps truly dynamic!

Share