📐 Layout Widgets — Arrange Your Widgets Beautifully
🧒 What Are Layout Widgets? (The Bookshelf Analogy!)
Imagine Arranging Books on a Shelf...
In the last lesson, you created a single Tile widget. But the Birdle game needs 25 tiles arranged in a 5×5 grid! How do you tell Flutter where to put each tile?
That's where layout widgets come in! They're like bookshelves for your widgets:
Row
Arranges children horizontally — like books lined up left to right on a single shelf.
Column
Arranges children vertically — like books stacked top to bottom in a pile.
Together!
Combine Rows and Columns to create grids — like a whole bookshelf with multiple shelves!
Here's the secret: A grid is just a Column of Rows! Each row is a shelf, and the column stacks those shelves on top of each other.
Alignment — Telling Widgets WHERE to Sit
When you put widgets in a Row or Column, you need to tell Flutter how to space them out. There are two types of alignment:
📏 MainAxisAlignment
Along the main direction:
- For a Row (horizontal): controls left↔right positioning
- For a Column (vertical): controls top↕bottom positioning
📐 CrossAxisAlignment
Perpendicular to the main direction:
- For a Row (horizontal): controls top↕bottom positioning
- For a Column (vertical): controls left↔right positioning
- Main = the direction the widgets flow (along the Row/Column)
- Cross = the opposite direction (across the Row/Column)
- In a Row: Main is horizontal ↔️, Cross is vertical ↕️
- In a Column: Main is vertical ↕️, Cross is horizontal ↔️
The 5×5 Grid — It's Just a Column of 5 Rows!
The Birdle game board is a 5×5 grid. But Flutter doesn't have a "grid" widget (well, it does — GridView — but we're learning the fundamentals first!).
Here's how we build it:
Column of 5 Rows, each Row has 5 Tiles = 25 Tiles total! That's the entire game board. Simple, right?
1 Start With Your Existing Code
Make sure you have the Tile widget from Lesson 3 and the game.dart file ready. We're going to build on top of that foundation.
Step 1.1 Your Starting Point
Your main.dart should currently have:
- ✅
import 'game.dart';at the top - ✅ The
Tilewidget class - ✅ The
MainAppclass with a single Tile or a small test layout
If you need to catch up, go back to Lesson 3: Widget Fundamentals.
2 The Row Widget — Arrange Things Horizontally
A Row takes a list of children and places them side by side, from left to right.
Step 2.1 Your First Row — 5 Tiles Across
Let's replace the body of your app with a single Row containing 5 Tiles:
🔍 Create a Row of 5 Tiles
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(
body: Center(
child: Row( // ← Row arranges horizontally
mainAxisAlignment: MainAxisAlignment.center, // Center the row
children: [
Tile('B', HitType.hit),
SizedBox(width: 4),
Tile('I', HitType.partial),
SizedBox(width: 4),
Tile('R', HitType.miss),
SizedBox(width: 4),
Tile('D', HitType.miss),
SizedBox(width: 4),
Tile('S', HitType.partial),
],
),
),
),
);
}
What's happening:
Row(children: [...])— The Row widget takes a list of children. It puts them in a line, left to right.mainAxisAlignment: MainAxisAlignment.center— This centers the entire row horizontally on the screen. The tiles will be grouped together in the middle.SizedBox(width: 4)— Adds 4 pixels of empty space between each tile, so they don't touch each other.
Hot reload! You should see 5 colored squares in a horizontal line — B (green), I (yellow), R (gray), D (gray), S (yellow).
Step 2.2 Experiment with MainAxisAlignment
Try changing mainAxisAlignment to these values and hot reload after each to see the difference:
MainAxisAlignment.start
Pushes everything to the left (the start of the row).
MainAxisAlignment.center
Groups everything in the middle.
MainAxisAlignment.end
Pushes everything to the right.
MainAxisAlignment.spaceEvenly
Equal space between tiles AND at the edges.
3 The Column Widget — Stack Things Vertically
A Column takes a list of children and places them one below the other, from top to bottom.
Step 3.1 Stack Two Rows Vertically
Now let's wrap our Row inside a Column, and add a second Row below it:
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(
body: Center(
child: Column( // ← Column stacks vertically
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Row 1 — First guess
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Tile('B', HitType.hit),
SizedBox(width: 4),
Tile('I', HitType.partial),
SizedBox(width: 4),
Tile('R', HitType.miss),
SizedBox(width: 4),
Tile('D', HitType.miss),
SizedBox(width: 4),
Tile('S', HitType.partial),
],
),
SizedBox(height: 4), // ← Space between rows
// Row 2 — Second guess
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Tile('F', HitType.miss),
SizedBox(width: 4),
Tile('L', HitType.partial),
SizedBox(width: 4),
Tile('U', HitType.hit),
SizedBox(width: 4),
Tile('T', HitType.miss),
SizedBox(width: 4),
Tile('E', HitType.hit),
],
),
],
),
),
),
);
}
Hot reload! Now you see two rows of 5 tiles each, stacked vertically. The grid is starting to take shape!
MaterialApp → Scaffold → Center → Column → [Row (5 Tiles), SizedBox, Row (5 Tiles)]Notice how we're nesting widgets: a Column contains Rows, and each Row contains Tiles. This is the core pattern of Flutter layouts!
4 Build the Complete 5×5 Birdle Game Board
Now for the big moment — create all 5 rows with 5 tiles each for a total of 25 tiles!
Step 4.1 The Full 5×5 Grid Code
Here's the complete game board layout. Each row represents one guess attempt:
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Birdle 🐦'),
centerTitle: true,
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Row 1 — Guess #1
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Tile('B', HitType.hit), SizedBox(width: 4),
Tile('I', HitType.partial), SizedBox(width: 4),
Tile('R', HitType.miss), SizedBox(width: 4),
Tile('D', HitType.miss), SizedBox(width: 4),
Tile('S', HitType.partial),
]),
SizedBox(height: 4),
// Row 2 — Guess #2
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Tile('F', HitType.miss), SizedBox(width: 4),
Tile('L', HitType.partial), SizedBox(width: 4),
Tile('U', HitType.hit), SizedBox(width: 4),
Tile('T', HitType.miss), SizedBox(width: 4),
Tile('E', HitType.hit),
]),
SizedBox(height: 4),
// Row 3 — Guess #3 (all correct!)
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Tile('A', HitType.hit), SizedBox(width: 4),
Tile('B', HitType.hit), SizedBox(width: 4),
Tile('A', HitType.hit), SizedBox(width: 4),
Tile('C', HitType.hit), SizedBox(width: 4),
Tile('K', HitType.hit),
]),
SizedBox(height: 4),
// Row 4 — Empty (no guesses yet)
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Tile('', HitType.none), SizedBox(width: 4),
Tile('', HitType.none), SizedBox(width: 4),
Tile('', HitType.none), SizedBox(width: 4),
Tile('', HitType.none), SizedBox(width: 4),
Tile('', HitType.none),
]),
SizedBox(height: 4),
// Row 5 — Empty (no guesses yet)
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
Tile('', HitType.none), SizedBox(width: 4),
Tile('', HitType.none), SizedBox(width: 4),
Tile('', HitType.none), SizedBox(width: 4),
Tile('', HitType.none), SizedBox(width: 4),
Tile('', HitType.none),
]),
],
),
),
),
);
}
5 Understanding Your Widget Tree
Let's visualize what you just built — the complete widget tree for the Birdle game board:
📝 What You Learned Today
You just learned the most important layout skill in Flutter!
Row Widget
Used Row to arrange 5 Tiles horizontally (side by side) with SizedBox for spacing.
Column Widget
Used Column to stack 5 Rows vertically (one below the other).
MainAxisAlignment
Controlled positioning along the main direction — center, start, end, spaceEvenly.
Built a 5×5 Grid
Combined Column + Rows to create a complete game board with 25 Tile widgets!
🧠 Test Yourself!
Let's check your understanding of layouts:
Q1 If you want to arrange widgets horizontally (side by side), which widget should you use?
Q2 To build a 5×5 grid, you need a Column containing 5 Rows, each with 5 children. What is this pattern called?
📦 Project 1: Create a 3×3 Tic-Tac-Toe Board
Apply your layout skills to build a different grid — a tic-tac-toe board!
Objective: Build a 3×3 Grid of X's and O's
📋 Requirements:
- Create a Column with 3 Rows
- Each Row has 3 Tiles (9 tiles total)
- Use these letters: Row 1: X, O, X | Row 2: O, X, O | Row 3: X, O, X
- All tiles should use
HitType.none(white — it's a fresh board) - Add
SizedBox(height: 4)between rows andSizedBox(width: 4)between tiles - Center the entire board on screen
🎯 Expected Output:
A 3×3 grid of white tiles showing X and O in a tic-tac-toe pattern, centered on screen.
📦 Project 2: Build a Number Pad Layout (1-9)
Practice nesting layouts by building a calculator-style number pad!
Objective: Create a 3×3 Number Grid with a Title
📋 Requirements:
- Add a Text title above the grid saying "Number Pad" (bold, size 24)
- Below the title, create a 3×3 grid with numbers 1-9
- Row 1: 1, 2, 3 | Row 2: 4, 5, 6 | Row 3: 7, 8, 9
- All tiles should use
HitType.none - Add
SizedBox(height: 16)between the title and the grid - The entire layout should be centered
🎯 Expected Output:
A "Number Pad" title centered at the top, with a 3×3 grid of numbered tiles below it, all centered on screen.
Lesson Complete!
You built a complete 5×5 game grid using Rows and Columns! You now understand the core layout system that powers every Flutter app.
Click the button above to track your progress!