Day 19: Expanded, Flexible & Spacer
Stop getting "RenderFlex overflowed" errors! Learn Expanded vs Flexible vs Spacer in Flutter with live examples. Build responsive layouts that work on every device. đąđť
áááąáˇá UI ááąáŤáşáážáŹ ááąááŹááťáá˛áˇáĄá፠áĄááŻáśá¸ááźáŻááąáˇáážááá˛áˇ Container áá˝áąá Row áá˝áąá Column áá˝áąáĄááźáąáŹááşá¸ ááźáąáŹááźáŽá¸ááźáŽáááŻááąáŹáˇ ááŽááąáˇááąáŹáˇ Flutter áá˛áˇ Flexbox system áážáŹ áááŤáááźá áş Expanded, Flexible, Spacer áááŻáˇáĄááźáąáŹááşá¸ áááşááźááşáˇááĄáąáŹááşááŤá
Flutter áážáŹ UI áá˝áąá ááźáŽá¸ áááşááąáŹááşááźáŽááᯠoverflowed áááŻááźáŽá¸ áĄááŤáá˛áˇáĄáá˛áá˛áˇ áĄáąáŹááşáážáŹ ááźááŹá¸ááááŻááťááŻá¸ ááąáŤáşááŹááŹááᯠáá˝áąáˇáá°á¸ááźáááşáááşááŤáááşá

ááŤáááąáŹáˇ UI ááᯠáááşáážááşáá˛áˇáĄá፠áážááá˛áˇ width, height áá˝áąáááş ááťáąáŹáşáá˝áŹá¸ááźáŽá¸ UI á ááŹááŻááşáááŻáˇ ááŻááşááážááşá¸áááááąáŹáˇáá˛áˇáĄá፠ááźááąá¸ááŹáᲠááźá áşááŤáááşá Construction ááŻááşááąááááŻááᯠááŹáááŻáááŻáá˛áˇ ááźááąá¸ááąááŹááťááŻá¸ááŤá ááŽáááŻááťááŻá¸ error áá˝áą ááźááąáá˛áˇáĄá፠ááźáąáážááşá¸ááąá¸áááŻáˇáááŻááŤáááşá
ááŽááᯠerror ááťááŻá¸áá˝áą ááźáąáážááşá¸áááŻáˇáááŻáááş Flutter áá˛áˇ Flexbox system ááᯠááŹá¸áááşááŹá¸áááŻáˇ áááŻáĄááşááŤáááşá Expanded, Flexible áá˛áˇ Spacer áááŻáˇááᯠááŻáśá¸ááźáŽá¸ááąáŹáˇ áĄááąáŤáşáážáŹ ááźááŹá¸áááᯠerror áá˝áą áááąáŤáşáĄáąáŹááş UI áá˝áą áááşááąáŹááşáááŻáˇáááŤáááşá UI ááᲠuser áá˝áąáá˛áˇ device size áĄááťááŻá¸ááťááŻá¸áážáŹ áááŻáĄááşáááᯠáážáááźáŽá¸ ááŻááşááźáŽá¸ áĄááŻááşááŻááşááąáážáŹááŤá
Expanded
ááŤáááąáŹáˇ áĄááŻáśá¸áĄááťáŹá¸ááŻáśá¸áᲠááźá áşááŤáááşá áá°áˇáá˛áážáŹááŤáá˛áˇ child widget ááᯠááá˛áˇááąáᏠáĄááŻááşáá°áááŻáˇ áááşáážááşááťááşáá˛áˇáĄá፠áĄááŻáśá¸ááźáŻáááŻáˇ áááŤáááşá Expanded áááŻáá˛áˇ ááŹáááşáĄáááŻááşá¸áá˛â ááťá˛áˇáááŻáˇááá˛áˇááąáᏠáááŻááŻáśá¸ááᯠááťá˛áˇááźáŽá¸ááąáŹáˇ ááąááŹáá°áá˝áŹá¸áážáŹááŤá
Row(
children: [
const Icon(Icons.person, color: Colors.blue),
const SizedBox(width: 10),
const Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text("User Name", style: TextStyle(fontWeight: FontWeight.bold)),
Text(
"This is a very long post description that would normally cause overflow!",
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
),
const Icon(Icons.more_vert),
],
)
flex áááąáŹáˇ Expanded widget áááŻáááşáááŻááźáŽá¸ ááŻáśá¸ááźáá˛áˇáĄá፠áááş widget á áááşááąáŹááşáá expand ááŻááşááá˛áááŻáᏠáááşáážááşááąá¸ááŹááťááŻá¸ááŤá
Column(
children: [
Expanded(flex: 3, child: Container(color: Colors.red)), // 75%
Expanded(flex: 1, child: Container(color: Colors.blue)), // 25%
],
)Flexible
ááŤáááąáŹáˇ expanded áĄááŻááşááŻááşááŻáśáá˛áˇ áĄáááşá¸áááş áááşááŤáááşá áá°áˇáááŻááąáŹáˇ ááá˛áˇááąááŹáááş ááąá¸ááźáŽá¸ááąáŹáˇ áááŻáĄááşáááąáŹááşáᲠáááşááąáŹááşááťááşáá˛áˇáĄá፠áĄááŻáśá¸ááźáŻááŤáááşá
Container(
height: 100,
color: Colors.grey[200],
child: Row(
children: [
Container(width: 50, color: Colors.red),
Flexible(
child: Container(
color: Colors.orange,
width: 80, // ⥠THIS IS THE KEY DIFFERENCE!
child: Center(
child: Text('FLEXIBLE\n"I only take what I need!"',
textAlign: TextAlign.center,
style: TextStyle(fontWeight: FontWeight.bold),
),
),
),
),
Container(width: 50, color: Colors.blue),
],
),
),
Flexible widget áážáŹ fit áááŻáá˛áˇ properties áᲠáážáááŤáááş ááŤáááąáŹáˇ flex á áááşáááŻáĄááŻááşááŻááşáážáŹáᲠáááşáážááşááąá¸áááŻáˇ áááŹááťááŻá¸ááŤá fit ááᯠFlexFit.tight áááŻáˇ ááąá¸áááŻááşáááş Expanded áá˛áˇ áĄááŻááşááŻááşááŻáś áá°áá˝áŹá¸ááŤááááşáˇáááşá fit ááᯠFlexFit.loose áá˛áˇ áĄááťáŹá¸ááŻáśá¸ áááşáážááşááźáŽá¸ áĄááŻáśá¸ááźáŻááŤáááşá default behaviour áᲠááźá
áşááŤáááşá
class FlexFitComparison extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Flexible with FlexFit.tight (acts like Expanded)'),
Row(
children: [
Container(width: 50, color: Colors.red),
Flexible(
fit: FlexFit.tight, // đ FORCES full expansion
child: Container(
color: Colors.purple,
child: Text('FlexFit.tight'),
),
),
Container(width: 50, color: Colors.blue),
],
),
SizedBox(height: 20),
Text('Flexible with FlexFit.loose (default - respects child size)'),
Row(
children: [
Container(width: 50, color: Colors.red),
Flexible(
fit: FlexFit.loose, // đ Allows child to be smaller
child: Container(
color: Colors.orange,
width: 100,
child: Text('FlexFit.loose'),
),
),
Container(width: 50, color: Colors.blue),
],
),
],
);
}
}
Expanded(child: Widget()) = Flexible(fit: FlexFit.tight, child: Widget())
Spacer
ááŤáááąáŹáˇ child áááşáážááşááąá¸áááŻáˇááááŻáá˛áˇ expanded widget áááŻáˇ ááźáąáŹáááŻáˇáááŤáááşá ááá˛áˇááąááŹááᯠáá°ááźáŽá¸ááąáŹáˇ áááźáŹá¸ component áá˝áąááᯠáááşáᏠáá˝ááşá¸áááŻáˇ áááŻáĄááşááŹááťááŻá¸áážáŹ áĄááŻáśá¸ááźáŻááŤáááşá
ááŽáážáŹááᯠText áááŻááźáŹá¸áážáŹ Spacer áááŻááźáŽá¸ áááşáˇááąá¸áááŻááşáᏠááźá
áşáá˛áˇáĄáá˝ááş áááşááŹááᯠáá˝ááşá¸ááąá¸ááąáážáŹáᲠááźá
áşááŤáááşá
Row(
children: [
Text('Left'),
Spacer(), // đ Pushes everything apart!
Text('Right'),
],
)
Spacer() = Expanded(child: SizedBox())ááŤáááŻáááşááąáŹáˇ ááááşáˇáááşáá˝áąáˇ UI áááŻááąáŹááşááᯠááťá˝ááşááąáŹáşáááŻáˇ ááąáˇááŹááźáŽá¸ááŹá¸ concept áá˝áą áá˛áˇ ááąá¸ááźááşáˇááĄáąáŹááşááŤá

class SocialMediaPostCard extends StatelessWidget {
const SocialMediaPostCard({super.key});
@override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.all(16),
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
CircleAvatar(
radius: 24,
backgroundImage: NetworkImage('https://i.pravatar.cc/150?img=1'),
),
SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Sarah Johnson',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
overflow: TextOverflow.ellipsis,
),
Text(
'2 hours ago ⢠San Francisco, CA',
style: TextStyle(
color: Colors.grey[600],
fontSize: 12,
),
overflow: TextOverflow.ellipsis,
),
],
),
),
IconButton(
icon: Icon(Icons.more_horiz),
onPressed: () {},
),
],
),
SizedBox(height: 12),
Text(
'Just launched my new Flutter app! đ Check out this amazing UI I built using Expanded, Flexible, and Spacer widgets. The responsiveness is incredible across all devices!',
style: TextStyle(fontSize: 14),
),
SizedBox(height: 12),
ClipRRect(
borderRadius: BorderRadius.circular(8),
child: AspectRatio(
aspectRatio: 16 / 9,
child: Container(
color: Colors.blue[100],
child: Icon(Icons.image, size: 64, color: Colors.blue[300]),
),
),
),
SizedBox(height: 16),
Row(
children: [
Flexible(
child: Chip(
label: Text('Flutter'),
backgroundColor: Colors.blue[100],
labelStyle: TextStyle(fontSize: 12),
),
),
SizedBox(width: 8),
Flexible(
child: Chip(
label: Text('Mobile Dev'),
backgroundColor: Colors.green[100],
labelStyle: TextStyle(fontSize: 12),
),
),
SizedBox(width: 8),
Flexible(
child: Chip(
label: Text('UI/UX'),
backgroundColor: Colors.orange[100],
labelStyle: TextStyle(fontSize: 12),
),
),
Spacer(),
Icon(Icons.bookmark_border, color: Colors.grey[600]),
],
),
Divider(height: 24),
Row(
children: [
Expanded(
flex: 2,
child: _StatItem(
icon: Icons.favorite_border,
count: '1.2K',
label: 'Likes',
),
),
Expanded(
flex: 2,
child: _StatItem(
icon: Icons.comment_outlined,
count: '234',
label: 'Comments',
),
),
Expanded(
flex: 2,
child: _StatItem(
icon: Icons.share_outlined,
count: '89',
label: 'Shares',
),
),
Spacer(flex: 1),
],
),
Divider(height: 24),
Row(
children: [
Expanded(
child: OutlinedButton.icon(
onPressed: () {},
icon: Icon(Icons.favorite_border, size: 18),
label: Text('Like'),
style: OutlinedButton.styleFrom(
foregroundColor: Colors.pink,
),
),
),
SizedBox(width: 8),
Expanded(
child: OutlinedButton.icon(
onPressed: () {},
icon: Icon(Icons.comment_outlined, size: 18),
label: Text('Comment'),
style: OutlinedButton.styleFrom(
foregroundColor: Colors.blue,
),
),
),
SizedBox(width: 8),
Flexible(
child: OutlinedButton.icon(
onPressed: () {},
icon: Icon(Icons.share_outlined, size: 18),
label: Text('Share'),
style: OutlinedButton.styleFrom(
foregroundColor: Colors.green,
),
),
),
],
),
],
),
),
);
}
}
class _StatItem extends StatelessWidget {
final IconData icon;
final String count;
final String label;
const _StatItem({
required this.icon,
required this.count,
required this.label,
});
@override
Widget build(BuildContext context) {
return Column(
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon, size: 20, color: Colors.grey[700]),
SizedBox(width: 4),
Text(
count,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
],
),
SizedBox(height: 4),
Text(
label,
style: TextStyle(
color: Colors.grey[600],
fontSize: 12,
),
),
],
);
}
}ááŤáááąáŹáˇ áĄááŻáá ááąáˇááŹááźáŽá¸áá˛áˇ logic áá˝áąáá˛áˇ ááąá¸ááŹá¸ááŹáᲠááźá áşááŤáááşá
ááŽááąáˇ Day 19 áĄáá˝ááşáááąáŹáˇ ááŽááąáŹááşáᲠááźá áşááŤáááşá áĄááŻáśá¸áá áááşááąá¸áá˛áˇáĄáá˝ááş áĄááťáŹá¸ááźáŽá¸ ááťáąá¸áá°á¸áááşááŤáááşá ááŹá¸ááááşááŹáá˝áą áĄáááşáááźáąááŹáá˝áą áážááá˛áˇáááşáᲠáĄáąáŹááşáážáŹááąá¸ááŹá¸áá˛áˇ discord server áá˛áážáŹ ááŹááąáŹááşáá˝áąá¸áá˝áąá¸áááŻááşááŤáááşá ááąáŹááşááąáˇáá˝áąáážáŹáᲠáááşáááşááźáŽá¸ sharing ááŻááşáá˝áŹá¸ááąá¸áá˝áŹá¸áážáŹ ááźá áşáá˛áˇáĄáá˝ááş subscribe ááŻááşááŹá¸áááŻáˇ ááááşááąáŤáşááŤáááşá
- Youtube: https://www.youtube.com/@arkarmintun
- Newsletter: https://arkar.dev/
- Discord: https://discord.gg/3xUJ6k6dkH