DEV Community

Ge Ji
Ge Ji

Posted on

Flutter Lesson 4: Layout Fundamentals: Row, Column, Stack

In Flutter, layout is the core of building interfaces. No matter how complex an interface is, it's composed of basic layout widgets combined together. In this lesson, we'll detailedly explain the most commonly used layout widgets in Flutter, including linear layouts (Row/Column), stack layouts (Stack), and auxiliary layout widgets, helping you master the basic ability of building interfaces.

1. Linear Layouts: Row and Column

Linear layout is the most commonly used layout method, arranging child widgets in either horizontal direction (Row) or vertical direction (Column).

1. Row: Arrange Children Horizontally

The Row widget is used to arrange child widgets in the horizontal direction. Its simplified constructor is as follows:

Row({
  Key? key,
  MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start, // Main axis alignment
  CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center, // Cross axis alignment
  MainAxisSize mainAxisSize = MainAxisSize.max, // Main axis size (fill parent or wrap children)
  VerticalDirection verticalDirection = VerticalDirection.down, // Vertical ordering
  TextDirection? textDirection, // Horizontal ordering (affects start/end judgment)
  List<Widget> children = const [], // List of child widgets
})
Enter fullscreen mode Exit fullscreen mode

Example Code:

Row(
  children: [
    Container(width: 50, height: 50, color: Colors.red),
    Container(width: 60, height: 60, color: Colors.green),
    Container(width: 70, height: 70, color: Colors.blue),
  ],
)
Enter fullscreen mode Exit fullscreen mode

When run, you'll see three colored blocks arranged horizontally in sequence.

2. Column: Arrange Children Vertically

Column is used exactly like Row, with the only difference being that it arranges child widgets in the vertical direction:

Column(
  children: [
    Container(width: 50, height: 50, color: Colors.red),
    Container(width: 60, height: 60, color: Colors.green),
    Container(width: 70, height: 70, color: Colors.blue),
  ],
)
Enter fullscreen mode Exit fullscreen mode

3. Main Axis and Cross Axis

Understanding the main axis and cross axis is key to mastering linear layouts:

  • Main axis: The direction in which widgets are arranged
    • The main axis of Row is the horizontal direction (left-right)
    • The main axis of Column is the vertical direction (top-bottom)
  • Cross axis: The direction perpendicular to the main axis
    • The cross axis of Row is the vertical direction (top-bottom)
    • The cross axis of Column is the horizontal direction (left-right)

2. Alignment: MainAxisAlignment and CrossAxisAlignment

Alignment allows precise control of the position of child widgets on the main and cross axes.

1. Main Axis Alignment (MainAxisAlignment)

Controls how child widgets are arranged along the main axis. Common values include:

  • start: Align along the start of the main axis (left for Row, top for Column)
  • end: Align along the end of the main axis (right for Row, bottom for Column)
  • center: Center alignment on the main axis
  • spaceBetween: Evenly distribute space between children (with end children touching edges)
  • spaceAround: Evenly distribute space around children (space at ends is half of middle spaces)
  • spaceEvenly: Evenly distribute all space (including at ends)

Example (Row + spaceBetween):

Row(
  mainAxisAlignment: MainAxisAlignment.spaceBetween,
  children: [
    Container(width: 50, height: 50, color: Colors.red),
    Container(width: 50, height: 50, color: Colors.green),
    Container(width: 50, height: 50, color: Colors.blue),
  ],
)
Enter fullscreen mode Exit fullscreen mode

2. Cross Axis Alignment (CrossAxisAlignment)

Controls how child widgets are arranged along the cross axis. Common values include:

  • start: Align along the start of the cross axis
  • end: Align along the end of the cross axis
  • center: Center alignment on the cross axis (default value)
  • stretch: Stretch children to fill the cross axis (requires children to have no fixed size)
  • baseline: Align by baseline (only effective for Row, related to text baseline)

Example (Row + stretch):

Row(
  crossAxisAlignment: CrossAxisAlignment.stretch, // Stretch vertically
  children: [
    Container(width: 50, color: Colors.red), // No height specified, will be stretched
    Container(width: 50, height: 60, color: Colors.green),
    Container(width: 50, height: 70, color: Colors.blue),
  ],
)
Enter fullscreen mode Exit fullscreen mode

3. Stack Layout: Stack and Positioned

When you need child widgets to display in a stack (such as text over an image), use the combination of Stack and Positioned.

1. Stack: Stacking Child Widgets

Stack stacks child widgets in order (later added widgets appear on top). Its simplified constructor is as follows:

Stack({
  Key? key,
  AlignmentGeometry alignment = Alignment.center, // Alignment for unpositioned children
  TextDirection? textDirection,
  StackFit fit = StackFit.loose, // How children fit into the stack
  Clip clipBehavior = Clip.hardEdge, // Whether to clip content outside bounds
  List<Widget> children = const [],
})
Enter fullscreen mode Exit fullscreen mode

Basic Example:

Stack(
  children: [
    // Bottom red container
    Container(width: 200, height: 200, color: Colors.red),
    // Middle green container (on top of red)
    Container(width: 150, height: 150, color: Colors.green),
    // Top blue container (on top of all)
    Container(width: 100, height: 100, color: Colors.blue),
  ],
)
Enter fullscreen mode Exit fullscreen mode

2. Positioned: Positioning Child Widgets

Positioned is used to precisely position child widgets within a Stack and must be a direct child of Stack. Common properties:

  • left: Distance from the left edge of the Stack
  • right: Distance from the right edge of the Stack
  • top: Distance from the top edge of the Stack
  • bottom: Distance from the bottom edge of the Stack
  • width/height: Specify the width and height of the child widget (optional)

Example:

Stack(
  children: [
    Container(width: 200, height: 200, color: Colors.grey),
    // Positioned at top-left
    Positioned(
      left: 10,
      top: 10,
      child: Container(width: 50, height: 50, color: Colors.red),
    ),
    // Positioned at bottom-right
    Positioned(
      right: 10,
      bottom: 10,
      child: Container(width: 50, height: 50, color: Colors.blue),
    ),
  ],
)
Enter fullscreen mode Exit fullscreen mode

4. Common Layout Auxiliary Widgets

These widgets don't handle layout themselves but help adjust the position, size, etc., of child widgets.

1. Padding: Inner Spacing

Adds inner padding to a child widget (distance between child and parent container edges):

Padding(
  padding: EdgeInsets.all(16), // Add 16px padding to all four directions
  // Can also set individually: EdgeInsets.only(left: 10, top: 20)
  child: Container(width: 100, height: 100, color: Colors.red),
)
Enter fullscreen mode Exit fullscreen mode

Common EdgeInsets constructors:

  • all(value): Uniform value for all sides
  • only(left, top, right, bottom): Set individual sides
  • symmetric(horizontal, vertical): Symmetric horizontal/vertical settings

2. Margin: Outer Spacing

There's no separate Margin widget in Flutter. It's implemented through the margin property of Container (distance between child and other widgets):

Container(
  margin: EdgeInsets.all(10), // Outer margin
  padding: EdgeInsets.all(10), // Inner padding
  color: Colors.grey,
  child: Container(width: 50, height: 50, color: Colors.red),
)
Enter fullscreen mode Exit fullscreen mode

3. Center: Center Alignment

A simplified alignment widget, equivalent to Align(alignment: Alignment.center, child: ...):

Center(
  child: Container(width: 100, height: 100, color: Colors.green),
)
Enter fullscreen mode Exit fullscreen mode

4. Expanded: Fill Remaining Space

In Row or Column, Expanded makes the child widget fill the remaining space in the main axis direction, solving the problem of child widgets' total width/height exceeding the parent widget (overflow shows yellow line errors).

Basic Usage:

Row(
  children: [
    Container(width: 50, height: 50, color: Colors.red),
    Expanded( // Fills remaining space
      child: Container(height: 50, color: Colors.green),
    ),
    Container(width: 50, height: 50, color: Colors.blue),
  ],
)
Enter fullscreen mode Exit fullscreen mode

Proportional Allocation (flex):

Row(
  children: [
    Expanded(
      flex: 1, // Takes 1 part
      child: Container(height: 50, color: Colors.red),
    ),
    Expanded(
      flex: 2, // Takes 2 parts (total space divided into 3 parts)
      child: Container(height: 50, color: Colors.green),
    ),
  ],
)
Enter fullscreen mode Exit fullscreen mode

5. Comprehensive Example: Combined Layout

In actual development, layout widgets are usually used nested. Here's a simple user information card example:

Container(
  width: 300,
  padding: EdgeInsets.all(16),
  decoration: BoxDecoration(
    color: Colors.white,
    borderRadius: BorderRadius.circular(8),
    boxShadow: [BoxShadow(color: Colors.grey, blurRadius: 3)],
  ),
  child: Row( // Arrange avatar and info horizontally
    children: [
      // Avatar
      Container(
        width: 60,
        height: 60,
        decoration: BoxDecoration(
          color: Colors.blue,
          borderRadius: BorderRadius.circular(30),
        ),
      ),
      SizedBox(width: 12), // Spacing
      // Info area (arranged vertically)
      Expanded( // Fills remaining width
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start, // Left-aligned
          children: [
            Text("Zhang San", style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
            SizedBox(height: 4),
            Text("Flutter Developer", style: TextStyle(color: Colors.grey)),
          ],
        ),
      ),
      // Right arrow
      Icon(Icons.arrow_right, color: Colors.grey),
    ],
  ),
)
Enter fullscreen mode Exit fullscreen mode

Top comments (0)