Spacer
Understand how to create flexible spacing between widgets.
What is it?
Spacer is a widget that creates flexible space between children of a Row, Column, or Flex. It takes up all available space in its direction, pushing other widgets apart. Spacer is the simplest way to add flexible spacing without using Expanded with empty containers.
Why does it exist?
Spacer exists to:
- Create flexible spacing between widgets
- Push widgets apart in flex layouts
- Distribute available space
- Simplify layout spacing
- Replace Expanded with empty Container
- Create responsive gaps
- Align widgets to ends
Basic Spacer
Spacer takes up available space.
// Basic Spacer usage
class BasicSpacer extends StatelessWidget {
const BasicSpacer({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: [
// 1. Spacer in Row
Container(
height: 80,
color: Colors.grey[200],
child: Row(
children: [
Container(width: 50, height: 50, color: Colors.red),
const Spacer(),
Container(width: 50, height: 50, color: Colors.blue),
],
),
),
const SizedBox(height: 20),
// 2. Spacer in Column
Container(
height: 150,
color: Colors.grey[200],
child: Column(
children: [
Container(height: 30, color: Colors.red),
const Spacer(),
Container(height: 30, color: Colors.green),
const Spacer(),
Container(height: 30, color: Colors.blue),
],
),
),
const SizedBox(height: 20),
// 3. Multiple Spacers
Container(
height: 80,
color: Colors.grey[200],
child: Row(
children: [
Container(width: 50, height: 50, color: Colors.red),
const Spacer(),
Container(width: 50, height: 50, color: Colors.green),
const Spacer(),
Container(width: 50, height: 50, color: Colors.blue),
],
),
),
],
);
}
}
// Spacer properties:
// 1. flex - How much space to take (default: 1)
// 2. child - No child (Spacer is empty)
What's happening here? - Spacer takes available space - Pushes widgets to ends - Multiple Spacers share space - Works in Row and Column - Simple and clean
Spacer vs SizedBox
Comparing Spacer with SizedBox for spacing.
// Spacer vs SizedBox
class SpacerVsSizedBox extends StatelessWidget {
const SpacerVsSizedBox({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: [
// 1. Spacer - Flexible space
Container(
height: 80,
color: Colors.grey[200],
child: Row(
children: [
const Text('Left'),
const Spacer(),
const Text('Right'),
],
),
),
const SizedBox(height: 10),
// 2. SizedBox - Fixed space
Container(
height: 80,
color: Colors.grey[200],
child: Row(
children: [
const Text('Left'),
const SizedBox(width: 100), // Fixed space
const Text('Right'),
],
),
),
const SizedBox(height: 10),
// 3. Multiple Spacers with flex
Container(
height: 80,
color: Colors.grey[200],
child: Row(
children: [
const Text('Left'),
const Spacer(flex: 2),
const Text('Center'),
const Spacer(flex: 1),
const Text('Right'),
],
),
),
],
);
}
}
// When to use:
// Spacer: Flexible, responsive spacing
// SizedBox: Fixed, predictable spacing
// Spacer adapts to available space
// SizedBox has fixed size
What's happening here? - Spacer: flexible, responsive - SizedBox: fixed, predictable - Spacer adapts to parent - SizedBox has fixed dimension - Choose based on need
Spacer with Flex Factors
Flex factors control space distribution.
// Spacer with flex factors
class SpacerFlexFactor extends StatelessWidget {
const SpacerFlexFactor({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: [
// 1. Equal flex (1:1)
Container(
height: 80,
color: Colors.grey[200],
child: Row(
children: [
const Text('Left'),
const Spacer(),
const Text('Center'),
const Spacer(),
const Text('Right'),
],
),
),
const SizedBox(height: 10),
// 2. Different flex (2:1)
Container(
height: 80,
color: Colors.grey[200],
child: Row(
children: [
const Text('Left'),
const Spacer(flex: 2),
const Text('Center'),
const Spacer(flex: 1),
const Text('Right'),
],
),
),
const SizedBox(height: 10),
// 3. Single Spacer
Container(
height: 80,
color: Colors.grey[200],
child: Row(
children: [
const Text('Left'),
const Spacer(),
const Text('Right'),
],
),
),
],
);
}
}
// Flex factor effects:
// Higher flex = more space
// Spacer(flex: 2) takes twice the space
// Useful for proportional spacing
What's happening here? - flex controls space amount - Higher flex = more space - Proportional distribution - Flexible spacing control
Spacer in Different Layouts
Spacer works in various flex layouts.
// Spacer in different contexts
class SpacerInLayouts extends StatelessWidget {
const SpacerInLayouts({super.key});
@override
Widget build(BuildContext context) {
return Column(
children: [
// 1. App bar with Spacer
Container(
height: 56,
color: Colors.blue,
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
children: [
const Icon(Icons.menu, color: Colors.white),
const SizedBox(width: 16),
const Text(
'Title',
style: TextStyle(
color: Colors.white,
fontSize: 20,
),
),
const Spacer(),
const Icon(Icons.search, color: Colors.white),
const SizedBox(width: 16),
const Icon(Icons.more_vert, color: Colors.white),
],
),
),
const SizedBox(height: 20),
// 2. Centered with Spacer
Container(
height: 100,
color: Colors.grey[200],
child: Row(
children: [
const Spacer(),
const Text('Center'),
const Spacer(),
],
),
),
const SizedBox(height: 20),
// 3. Three sections with Spacer
Container(
height: 100,
color: Colors.grey[200],
child: Row(
children: [
Container(
width: 80,
color: Colors.red,
child: const Center(child: Text('Left')),
),
const Spacer(),
Container(
width: 80,
color: Colors.green,
child: const Center(child: Text('Center')),
),
const Spacer(),
Container(
width: 80,
color: Colors.blue,
child: const Center(child: Text('Right')),
),
],
),
),
],
);
}
}
What's happening here? - App bar with Spacer - Centering with Spacer - Three-section layout - Flexible and clean
Real-World Examples
Common patterns using Spacer.
// 1. App bar with actions
class AppBarWithActions extends StatelessWidget {
const AppBarWithActions({super.key});
@override
Widget build(BuildContext context) {
return Container(
height: 56,
color: Colors.blue,
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Row(
children: [
const Icon(Icons.arrow_back, color: Colors.white),
const SizedBox(width: 16),
const Text(
'Screen Title',
style: TextStyle(
color: Colors.white,
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
const Spacer(),
IconButton(
icon: const Icon(Icons.search, color: Colors.white),
onPressed: () {},
),
IconButton(
icon: const Icon(Icons.more_vert, color: Colors.white),
onPressed: () {},
),
],
),
);
}
}
// 2. Bottom action bar
class BottomActionBar extends StatelessWidget {
const BottomActionBar({super.key});
@override
Widget build(BuildContext context) {
return Container(
height: 80,
padding: const EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 8,
),
],
),
child: Row(
children: [
const Icon(Icons.favorite_border, size: 30),
const SizedBox(width: 16),
const Icon(Icons.comment_outlined, size: 30),
const Spacer(),
ElevatedButton(
onPressed: () {},
child: const Text('Buy Now'),
),
],
),
);
}
}
// 3. Profile header
class ProfileHeader extends StatelessWidget {
const ProfileHeader({super.key});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(16),
child: Row(
children: [
const CircleAvatar(
radius: 30,
backgroundImage: NetworkImage('https://example.com/avatar.jpg'),
),
const SizedBox(width: 16),
const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'John Doe',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
Text(
'Flutter Developer',
style: TextStyle(
color: Colors.grey,
fontSize: 14,
),
),
],
),
const Spacer(),
IconButton(
icon: const Icon(Icons.edit),
onPressed: () {},
),
],
),
);
}
}
// 4. Quiz progress bar
class QuizProgress extends StatelessWidget {
const QuizProgress({super.key});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(16),
color: Colors.grey[100],
child: Row(
children: [
const Text(
'Question 3 of 10',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
const Spacer(),
// Progress dots
...List.generate(5, (index) {
return Container(
width: 12,
height: 12,
margin: const EdgeInsets.symmetric(horizontal: 4),
decoration: BoxDecoration(
color: index < 3 ? Colors.blue : Colors.grey[300],
shape: BoxShape.circle,
),
);
}),
const Spacer(),
const Text(
'75%',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.blue,
),
),
],
),
);
}
}
What's happening here? - App bar with actions pushed right - Bottom bar with centered actions - Profile header with edit button - Quiz progress with spacing
Best Practices
Use Spacer for Flexible Spacing
// Good - Flexible spacing
@override
Widget build(BuildContext context) {
return Row(
children: [
const Text('Left'),
const Spacer(),
const Text('Right'),
],
);
}
Use Multiple Spacers for Distribution
// Good - Multiple spacers
@override
Widget build(BuildContext context) {
return Row(
children: [
const Text('Left'),
const Spacer(),
const Text('Center'),
const Spacer(),
const Text('Right'),
],
);
}
Use Flex Factors for Proportions
// Good - Proportional spacing
@override
Widget build(BuildContext context) {
return Row(
children: [
const Text('Left'),
const Spacer(flex: 2),
const Text('Center'),
const Spacer(flex: 1),
const Text('Right'),
],
);
}
Common Mistakes
Using Spacer Outside Flex
Wrong:
// Error: Spacer must be inside Flex
Column(
children: [
Text('Top'),
const Spacer(), // Error
Text('Bottom'),
],
)
Correct:
// Spacer inside Flex
Column(
children: [
const Text('Top'),
const Expanded(
child: Center(
child: Text('Middle'),
),
),
const Text('Bottom'),
],
)
Overusing Spacer
Wrong:
// Too many spacers
Row(
children: [
const Spacer(),
const Spacer(), // Redundant
const Text('Center'),
const Spacer(),
const Spacer(), // Redundant
],
)
Correct:
// Clean spacing
Row(
children: [
const Spacer(),
const Text('Center'),
const Spacer(),
],
)
Summary
Spacer creates flexible spacing in flex layouts. Use Spacer for responsive gaps, pushing widgets to ends, and distributing space. Spacer is cleaner than Expanded with empty containers and adapts to available space.
Next Steps
Did You Know?
- Spacer = Expanded with empty child
- Spacer only works in Flex (Row/Column)
- flex controls space distribution
- Spacer adapts to available space
- Multiple Spacers share space
- Spacer is more readable than Expanded
- Spacer has no child
- Spacer is responsive by default