Flutter is known for its fast development cycle, expressive UI, and powerful widget-based architecture. But at the heart of every Flutter interface lies one fundamental skill: mastering layout widgets. Whether you're building a simple screen or a complex responsive interface, understanding how Row, Column, and Stack work — and how to combine them — is essential.
In this tutorial, you’ll learn:
-
How Row, Column, and Stack layout widgets work
-
Key properties like
mainAxisAlignment,crossAxisAlignment, andfit -
When to use each widget and common pitfalls
-
How to build adaptive and responsive UIs using
MediaQuery,LayoutBuilder, and responsive patterns -
Hands-on examples with code snippets you can use in your next Flutter app
By the end, you’ll have a solid foundation to design professional layouts in Flutter — from simple static screens to dynamic, responsive designs.
Understanding Flutter Layout Basics
Before diving into Row, Column, and Stack, it's important to understand how Flutter’s layout system works. Flutter doesn’t use HTML or CSS. Instead, it relies on a widget-based render tree, where each widget defines its own layout behavior.
Below are the key layout concepts you must know:
1. The Widget Tree and Render Tree
Flutter builds your UI as a tree of widgets, where every piece of UI — text, buttons, padding, layout containers — is a widget. During rendering, Flutter converts these widgets into:
-
Element Tree → manages widget lifecycle
-
Render Tree → performs actual layout (size + position)
Understanding this helps explain why some widgets size themselves differently depending on their parents.
2. Constraints: The Golden Rule of Flutter Layout
Flutter's layout follows the Constraints → Size → Position model:
-
Parent gives child constraints
-
Max width/height
-
Min width/height
-
-
The child chooses a size within those constraints
-
The parent positions the child
This is known as the Flutter Layout Gold Rule:
Parent sets constraints → Child chooses size → Parent positions child.
Understanding constraints helps resolve many layout issues, such as overflow, alignment problems, or unexpected widget behavior.
3. Types of Widgets in Layout
Flutter has three primary widget categories:
i. Single-child layout widgets
Examples:
-
Container -
Padding -
Align -
Center -
SizedBox
Used when you want to control or style a single child.
ii. Multi-child layout widgets
Examples:
-
Row -
Column -
Stack -
Wrap -
ListView
Used for arranging multiple widgets horizontally, vertically, stacked, or scrollable.
iii. Non-rendering widgets
Examples:
-
Expanded -
Flexible -
Spacer
These control the layout behavior inside Rows and Columns without rendering their own visual element.
4. Common Layout Problems and Why They Happen
Overflow (Yellow/Black Strip Error)
Occurs when:
-
Row/Column children exceed available space
-
Fixed-size widgets in small screens
-
Images or text are not wrapped
Unbounded Height or Width Error
Happens when:
-
Widgets try to expand inside scroll views
-
Containers are placed in infinite constraints without explicit size
Misalignment Issues
Often caused by:
-
Not using the correct
mainAxisAlignmentorcrossAxisAlignment -
Mixing flexible and inflexible children incorrectly
5. Demo Example: Visualizing Constraints
Container(
color: Colors.blue,
child: Center(
child: Container(
width: 200,
height: 100,
color: Colors.orange,
child: const Center(
child: Text("Constraints Demo"),
),
),
),
);
Here’s what happens:
-
The outer
Containertakes full width/height -
Centergives tight constraints to its child -
Inner container sizes themselves to 200×100
-
Text is centered due to
Center
Row — Horizontal Layout Mastery
Row is one of the most commonly used layout widgets in Flutter. It allows you to place widgets side by side horizontally. Mastering Row is crucial for building headers, menus, cards, toolbars, and responsive horizontal layouts.
1. What Is a Row?
A Row arranges its children left to right (or right to left depending on locale). By default, a Row takes up only the space it needs, unless inside widgets like Expanded, Flexible, or SizedBox.
2. Basic Row Example
Row(
children: const [
Icon(Icons.home, size: 40),
SizedBox(width: 12),
Text(
"Home",
style: TextStyle(fontSize: 20),
),
],
);
This simply places the icon and text next to each other.
3. Understanding Main Axis and Cross Axis
Main Axis → Horizontal
Controls how children are spaced left to right.
Cross Axis → Vertical
Controls how children are aligned top to bottom.
4. mainAxisAlignment Options
| Value | Behavior |
|---|---|
start |
Children align to the left |
center |
Center horizontally |
end |
Align to right |
spaceBetween |
Space distributed between children |
spaceAround |
Equal space around children |
spaceEvenly |
All spacing equal |
Example:
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text("A"),
Text("B"),
Text("C"),
],
);
5. crossAxisAlignment Options
| Value | Behavior |
|---|---|
start |
Align top |
center |
Center vertically |
end |
Align bottom |
stretch |
Children expand vertically (if possible) |
Example:
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: const [
Text("Short"),
Text("Much Taller Text", style: TextStyle(fontSize: 30)),
],
);
6. Handling Overflow in Rows
Rows can overflow if the children are too wide.
Solutions:
✔ Wrap text with Expanded
✔ Use Flexible
✔ Apply FittedBox
✔ Use Wrap widget instead (for responsive behavior)
7. Using Expanded and Flexible inside Row
Expanded forces a child to take up the remaining horizontal space:
Row(
children: const [
Expanded(
child: Text("This text takes all remaining space"),
),
Icon(Icons.info),
],
);
Flexible is similar but allows the child to size itself within the space:
Row(
children: const [
Flexible(
child: Text("Flexible text can wrap or shrink"),
),
Icon(Icons.star),
],
);
8. Example: Building a Simple App Header
Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
color: Colors.blue,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text(
"MyApp",
style: TextStyle(color: Colors.white, fontSize: 20),
),
Row(
children: [
Icon(Icons.search, color: Colors.white),
SizedBox(width: 16),
Icon(Icons.notifications, color: Colors.white),
],
),
],
),
);
This small snippet demonstrates a real-world use case: a responsive header bar.
9. When Not to Use Row
Avoid using Row when:
-
Content must wrap to the next line → use Wrap
-
You need a scrollable horizontal list → use ListView.horizontal
-
Dynamic content may grow unpredictably → use
ExpandedorFlexiblecarefully
Column — Vertical Layout Mastery
Just like Row arranges widgets horizontally, Column is used to arrange widgets from top to bottom. It’s one of the most essential widgets in Flutter for building screens, forms, dialogs, and stacked vertical content.
1. What Is a Column?
A Column arranges its children vertically. By default, a Column takes only the vertical space it needs, but its behavior changes depending on its parents, such as:
-
Expanded -
Flexible -
SingleChildScrollView -
SizedBox
Understanding its layout behavior is crucial to avoiding overflow errors.
2. Basic Column Example
Column(
children: const [
Text("Title", style: TextStyle(fontSize: 24)),
SizedBox(height: 10),
Text("Subtitle", style: TextStyle(fontSize: 16)),
],
);
This places text widgets one above the other with spacing.
3. Main Axis vs Cross Axis
Main Axis → Vertical
Controls how children are aligned top-to-bottom.
Cross Axis → Horizontal
Controls how children are aligned left-to-right.
4. mainAxisAlignment Options
| Value | Behavior |
|---|---|
start |
Align children to the top |
center |
Center vertically |
end |
Align children to the bottom |
spaceBetween |
Space is distributed between items |
spaceAround |
Equal spacing around children |
spaceEvenly |
Equal spacing everywhere |
Example:
Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: const [
Text("Item 1"),
Text("Item 2"),
Text("Item 3"),
],
);
5. crossAxisAlignment Options
| Value | Behavior |
|---|---|
start |
Left aligned |
center |
Centered horizontally |
end |
Right aligned |
stretch |
Children expand to fill horizontal space |
Example:
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ElevatedButton(
onPressed: () {},
child: const Text("Full Width Button"),
),
],
);
Using stretch makes children expand horizontally across the available width.
6. Using Expanded and Flexible inside Column
Expanded fills remaining vertical space:
Column(
children: const [
Text("Header", style: TextStyle(fontSize: 24)),
Expanded(
child: Center(
child: Text("Content Area"),
),
),
],
);
Flexible gives a child adjustable space without forcing full expansion:
Column(
children: const [
Flexible(
child: Text(
"Flexible content that adapts but doesn't force full height",
),
),
SizedBox(height: 20),
Text("Footer"),
],
);
7. Common Column Overflow Issues
Column overflow often occurs when:
-
Widgets exceed the screen height
-
You place too many large widgets
-
The keyboard appears and pushes the widgets upward
-
Fixed-size containers on small screens
Solutions:
✔ Wrap content with SingleChildScrollView
✔ Use Expanded or Flexible to control space
✔ Wrap inside SafeArea
✔ Use LayoutBuilder for responsive height decisions
8. Example: Building a Login Form Layout
Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
"Welcome Back!",
style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
),
const SizedBox(height: 20),
TextField(decoration: InputDecoration(labelText: "Email")),
const SizedBox(height: 16),
TextField(
obscureText: true,
decoration: InputDecoration(labelText: "Password"),
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () {},
child: const Text("Login"),
),
],
),
);
This example showcases a typical vertical layout used in many app screens.
9. When Not to Use Column
Avoid using Column when:
-
You expect content to overflow — use
ListVieworSingleChildScrollView -
You need responsive items that wrap — use
Wrap -
You require equal vertical spacing — consider
ExpandedorSpacer
Stack — Overlapping Widgets Like a Pro
While Row and Column arrange widgets linearly, Stack is used when you want to place widgets on top of each other, similar to absolute positioning in traditional UI frameworks. Stack is perfect for creating layered designs, banners, floating buttons, image overlays, and custom layouts that require precise positioning.
1. What Is a Stack?
A Stack positions its children relative to each other, allowing them to overlap. By default, children are placed in the top-left corner unless wrapped in a Positioned widget or aligned using Align.
2. Basic Stack Example
Stack(
children: [
Container(width: 200, height: 200, color: Colors.blue),
const Icon(Icons.star, size: 60, color: Colors.white),
],
);
The icon appears centered on top of the blue container by default sizing of the Stack child.
3. Using Positioned for Absolute Positioning
Positioned lets you define exact placements:
Stack(
children: [
Container(width: 300, height: 200, color: Colors.grey),
Positioned(
top: 20,
right: 20,
child: Icon(Icons.favorite, color: Colors.red, size: 40),
),
],
);
You can use properties like:
-
top,right,bottom,left -
width,height
4. Using Align for Relative Positioning
Align positions a widget using coordinates from -1.0 to 1.0 on both axes:
Stack(
children: const [
Align(
alignment: Alignment.bottomCenter,
child: Text("Bottom Text"),
),
Align(
alignment: Alignment.topRight,
child: Icon(Icons.info),
),
],
);
5. fit Property: Controlling Child Sizing
StackFit has three options:
StackFit.loose
Children take their natural size (default).
StackFit.expand
Children expand to fill available space.
Example:
Stack(
fit: StackFit.expand,
children: [
Container(color: Colors.purple),
Align(
alignment: Alignment.center,
child: Text("Centered Text", style: TextStyle(color: Colors.white)),
),
],
);
6. clipBehavior: Handling Overflow
By default, Stack allows overflow. If you want to clip, use:
clipBehavior: Clip.hardEdge
or:
clipBehavior: Clip.antiAlias
7. Common Use Cases for Stack
✔ App Banners
Image with text overlay.
✔ Floating Action Buttons
Button positioned above content.
✔ Profile Avatar Layouts
Overlapping avatar and decorative borders.
✔ Custom Cards
Icons or labels are placed on corners.
✔ Custom Shapes and UI Effects
Glow, shadows, background gradients.
8. Example: Building a Card with Image Overlay
SizedBox(
width: 300,
height: 200,
child: Stack(
children: [
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage("https://picsum.photos/300/200"),
fit: BoxFit.cover,
),
),
),
Positioned(
bottom: 16,
left: 16,
child: Container(
padding: const EdgeInsets.all(8),
color: Colors.black54,
child: const Text(
"Beautiful Landscape",
style: TextStyle(color: Colors.white, fontSize: 16),
),
),
),
],
),
);
This creates a beautiful image card with text overlay.
9. When Not to Use Stack
Avoid Stack when:
-
Layout should be responsive without fixed positions → prefer
AlignorExpanded -
Items should flow naturally → use
ColumnorRow -
Overlapping is unnecessary → avoid added complexity
-
Performance matters on long lists → Stack is heavier than linear containers
Building Responsive UI in Flutter
Modern apps run on devices of all sizes — small phones, tablets, foldables, desktops, and even the web. Flutter gives you powerful tools to build responsive and adaptive UIs that scale beautifully across screen sizes.
This section covers essential techniques and real-world patterns for responsive design in Flutter.
1. Responsive vs Adaptive UI
Responsive UI
Adjusts layout based on available space.
Example: switching from a one-column to a two-column layout.
Adaptive UI
Adjusts behavior/style based on platform.
Example: using Cupertino widgets on iOS, Material widgets on Android.
In this section, we focus on responsive layouts.
2. Using MediaQuery for Screen Dimensions
MediaQuery allows you to read important layout information:
-
Screen width and height
-
Orientation
-
Padding and safe area
-
Device pixel ratio
Example:
final size = MediaQuery.of(context).size;
final width = size.width; // screen width
final height = size.height; // screen height
3. Breakpoints: Defining Layout Rules
Breakpoints help control layout depending on screen width.
Common breakpoints:
| Device | Width |
|---|---|
| Small phones | < 360 px |
| Medium phones | 360–480 px |
| Tablets | 600–1024 px |
| Desktop | > 1024 px |
Example breakpoint logic:
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
if (width < 600) {
return buildMobileLayout();
} else if (width < 1024) {
return buildTabletLayout();
} else {
return buildDesktopLayout();
}
}
4. LayoutBuilder: The Most Powerful Responsive Tool
LayoutBuilder gives you the actual available width of the parent, which is more accurate than MediaQuery in many scenarios.
Example:
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return buildMobileLayout();
} else {
return buildTabletLayout();
}
},
);
5. Using Flexible, Expanded, and Spacer Responsively
These widgets help divide space proportionally.
Example:
Row(
children: const [
Expanded(flex: 3, child: Placeholder()),
Expanded(flex: 2, child: Placeholder()),
],
);
flex defines how much space each child gets relative to others.
6. Responsive Text Using FittedBox or MediaQuery
Using FittedBox:
FittedBox(
child: Text("Responsive Title"),
);
Using MediaQuery-based scaling:
Text(
"Title",
style: TextStyle(fontSize: MediaQuery.of(context).size.width * 0.05),
);
7. Wrap Widget for Auto-Wrapping Layouts
Use Wrap when Row/Column overflows or when you need fluid layouts.
Example:
Wrap(
spacing: 12,
runSpacing: 12,
children: List.generate(
10,
(index) => Chip(label: Text("Item $index")),
),
);
8. Responsive Grid Using GridView
SliverGridDelegateWithFixedCrossAxisCount:
GridView.count(
crossAxisCount: width < 600 ? 2 : 4,
);
Or more dynamic:
GridView(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200,
),
);
9. Example: Making a Two-Column Responsive Layout
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth < 600) {
return Column(
children: const [
Placeholder(fallbackHeight: 150),
SizedBox(height: 16),
Placeholder(fallbackHeight: 150),
],
);
}
return Row(
children: const [
Expanded(child: Placeholder()),
SizedBox(width: 16),
Expanded(child: Placeholder()),
],
);
},
);
Perfect for dashboards, product pages, or tablet layouts.
10. Example: Responsive Card Grid
GridView.count(
padding: const EdgeInsets.all(16),
crossAxisCount: width < 480
? 2
: width < 800
? 3
: 4,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
children: List.generate(
8,
(index) => Card(
child: Center(child: Text("Card $index")),
),
),
);
11. Techniques for Highly Adaptive Apps
✔ Use FractionallySizedBox for proportional sizing
✔ Use Align with fractional offsets
✔ Create custom breakpoints for your app
✔ Combine Row, Column, and Stack to form complex layouts
✔ Consider third-party responsive packages (optional)
Real-World Examples and Best Practices
Now that you understand Row, Column, Stack, and responsive techniques, let's combine everything into real-world examples. This section also covers best practices to help you avoid common pitfalls and write clean, scalable layouts in Flutter.
1. Example 1: Responsive Profile Header
A common app pattern: user profile with background, avatar, and actions.
SizedBox(
height: 250,
child: Stack(
fit: StackFit.expand,
children: [
// Background image
Image.network(
"https://picsum.photos/800/400",
fit: BoxFit.cover,
),
// Dark overlay
Container(color: Colors.black26),
// Profile content
Positioned(
left: 16,
bottom: 16,
child: Row(
children: [
const CircleAvatar(
radius: 40,
backgroundImage: NetworkImage("https://picsum.photos/200"),
),
const SizedBox(width: 16),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: const [
Text(
"John Doe",
style: TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
Text(
"@johndoe",
style: TextStyle(color: Colors.white70),
),
],
)
],
),
),
],
),
);
Concepts used:
-
Stackfor layering image + overlay + content -
Positionedfor placing profile info -
Row+Columnfor text layout
2. Example 2: Product Grid with Responsive Columns
LayoutBuilder(
builder: (context, constraints) {
int count = 2;
if (constraints.maxWidth > 600) count = 4;
if (constraints.maxWidth > 900) count = 6;
return GridView.count(
crossAxisCount: count,
padding: const EdgeInsets.all(16),
crossAxisSpacing: 12,
mainAxisSpacing: 12,
children: List.generate(
20,
(index) => Card(
elevation: 3,
child: Center(child: Text("Item $index")),
),
),
);
},
);
Concepts used:
-
Responsive breakpoints
-
Dynamic grid count
-
LayoutBuilderfor precision
3. Example 3: Complex App Dashboard Layout
LayoutBuilder(
builder: (context, constraints) {
bool isWide = constraints.maxWidth > 900;
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Sidebar
if (isWide)
SizedBox(
width: 250,
child: Column(
children: const [
ListTile(title: Text("Dashboard")),
ListTile(title: Text("Settings")),
ListTile(title: Text("Reports")),
],
),
),
// Main Content
Expanded(
child: Column(
children: [
Container(
height: 200,
margin: const EdgeInsets.all(16),
color: Colors.blue[200],
child: const Center(child: Text("Header Banner")),
),
Expanded(
child: GridView.count(
crossAxisCount: isWide ? 3 : 1,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
padding: const EdgeInsets.all(16),
children: List.generate(
6,
(index) => Container(
color: Colors.green[200],
child: Center(child: Text("Card $index")),
),
),
),
),
],
),
),
],
);
},
);
Concepts used:
-
Combining Row, Column, GridView
-
Sidebar layout that disappears on mobile
-
True multi-device layout
4. Example 4: Floating Button Over Content
Stack(
children: [
ListView(
padding: const EdgeInsets.all(16),
children: List.generate(
30,
(i) => ListTile(title: Text("Item $i")),
),
),
Positioned(
bottom: 20,
right: 20,
child: FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.add),
),
),
],
);
Concepts used:
-
Stack+Positioned -
Floating overlay on scrollable content
5. Best Practices for Flutter Layouts
i. Avoid deeply nested Rows/Columns
Too many nests → messy + slow.
💡 Combine with Wrap, Flex, or reorganize using smaller widgets.
ii. Use const whenever possible
Improves performance and reduces rebuild cost.
iii. Prefer Flexible over fixed sizes
Fixed sizes cause overflow issues on small screens.
iv. Use LayoutBuilder for complex responsive UI
More reliable than MediaQuery for container-level decisions.
v. Avoid unnecessary positioned values
Don’t hardcode pixel values unless necessary — use alignment or padding instead.
vi. Keep UI modular
Break complex UIs into widget classes:
class UserCard extends StatelessWidget { ... }
vii. Test layouts on multiple devices
Use:
-
Flutter DevTools layout inspector
-
Chrome responsive mode (for web)
-
Different device simulators
Conclusion
Mastering Flutter layout is one of the most important steps toward becoming an effective Flutter developer. With a strong understanding of Row, Column, Stack, and responsive layout techniques, you can build beautiful, scalable user interfaces that look great on any screen size — from small phones to large desktop monitors.
In this tutorial, you learned:
-
How Flutter’s layout system works through constraints, sizing, and positioning
-
How to use Row and Column for linear layouts
-
How to leverage Stack for layered, overlapping designs
-
How to implement a responsive UI using
MediaQuery,LayoutBuilder, breakpoints, grids, and flexible widgets -
How to build real-world UI patterns like profile headers, dashboards, and product grids
-
Best practices that help keep your code clean, modular, and future-proof
With these foundational tools, you’ll be able to create almost any UI in Flutter — from simple pages to complex app dashboards.
The next step is experimentation. Try combining multiple layout patterns from this guide, refactor your widgets into reusable components, and test your layouts across device sizes. The more you practice, the more intuitive the system becomes — and soon, designing responsive, elegant Flutter interfaces will feel effortless.
You can find the full source code on our GitHub.
That's just the basics. If you need more deep learning about Flutter and Dart, you can take the following cheap course:
- Flutter & Dart - The Complete Guide [2025 Edition]
- The Complete Flutter Development Bootcamp with Dart
- Complete Flutter Guide 2025: Build Android, iOS and Web apps
- Advanced Flutter: Build Enterprise-Ready Apps.
- Flutter , Nodejs, Express , MongoDB: Build Multi-Store App
- Flutter & Dart Essentials-Build Mobile Apps like a Pro
- Master Flutter with ML: Object Detection, OCR & Beyond
- Full-Stack Mobile Development: Flutter, Figma, and Firebase
- Dart & Flutter - Zero to Mastery [2025] + Clean Architecture
- Master Flame Game Engine with Flutter: Build 2D Mobile Games
Thanks!
