Welcome to Day 7 of the "Hundred Days of Flutter" course! Today, we'll dive deep into Flutter's layout widgets, focusing on how to create responsive and well-structured user interfaces using Row, Column, Expanded, and Flexible widgets.
The Row widget arranges its children horizontally in a line. It's one of the most commonly used layout widgets in Flutter.
Row(
children: [
Icon(Icons.star),
Text('Rating: 4.5'),
Icon(Icons.thumb_up),
],
)
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Left'),
Text('Center'),
Text('Right'),
],
)
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
height: 50,
width: 50,
color: Colors.red,
),
Container(
height: 100,
width: 50,
color: Colors.blue,
),
],
)
The Column widget arranges its children vertically in a line.
Column(
children: [
Text('First'),
Text('Second'),
Text('Third'),
],
)
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text('Top'),
Text('Middle'),
Text('Bottom'),
],
)
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
height: 50,
color: Colors.red,
),
Container(
height: 50,
color: Colors.blue,
),
],
)
The Expanded widget allows a child of a Row or Column to expand to fill the available space.
Row(
children: [
Container(
width: 50,
color: Colors.red,
),
Expanded(
child: Container(
color: Colors.blue,
),
),
Container(
width: 50,
color: Colors.green,
),
],
)
Row(
children: [
Expanded(
flex: 1,
child: Container(
color: Colors.red,
),
),
Expanded(
flex: 2,
child: Container(
color: Colors.blue,
),
),
Expanded(
flex: 1,
child: Container(
color: Colors.green,
),
),
],
)
The Flexible widget is similar to Expanded but allows its child to be smaller than the available space.
Row(
children: [
Flexible(
child: Container(
color: Colors.red,
),
),
Container(
width: 100,
color: Colors.blue,
),
Flexible(
child: Container(
color: Colors.green,
),
),
],
)
Row(
children: [
Flexible(
fit: FlexFit.loose,
child: Container(
width: 50,
color: Colors.red,
),
),
Flexible(
fit: FlexFit.tight,
child: Container(
color: Colors.blue,
),
),
],
)
Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: const EdgeInsets.all(16),
color: Colors.blue,
child: Row(
children: [
Icon(Icons.title, color: Colors.white),
const SizedBox(width: 8),
Expanded(
child: Text(
'Card Title',
style: TextStyle(color: Colors.white),
),
),
],
),
),
Padding(
padding: const EdgeInsets.all(16),
child: Text('Card content goes here'),
),
],
),
)
LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 600) {
return Row(
children: [
Expanded(
child: Container(
color: Colors.red,
child: Text('Left Panel'),
),
),
Expanded(
child: Container(
color: Colors.blue,
child: Text('Right Panel'),
),
),
],
);
} else {
return Column(
children: [
Container(
color: Colors.red,
child: Text('Top Panel'),
),
Container(
color: Colors.blue,
child: Text('Bottom Panel'),
),
],
);
}
},
)
Let's test your understanding of today's concepts:
What is the main difference between Expanded and Flexible widgets?
Which property in Row and Column determines how children are aligned along the main axis?
What happens when you use multiple Expanded widgets with different flex values?
Create a responsive navigation bar that:
Here's a starting point:
class ResponsiveNavBar extends StatelessWidget {
const ResponsiveNavBar({super.key});
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 600) {
return Row(
children: [
Expanded(
child: NavBarItem(
icon: Icons.home,
label: 'Home',
),
),
Expanded(
child: NavBarItem(
icon: Icons.search,
label: 'Search',
),
),
Expanded(
child: NavBarItem(
icon: Icons.person,
label: 'Profile',
),
),
],
);
} else {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
NavBarItem(
icon: Icons.home,
label: 'Home',
),
NavBarItem(
icon: Icons.search,
label: 'Search',
),
NavBarItem(
icon: Icons.person,
label: 'Profile',
),
],
);
}
},
);
}
}
class NavBarItem extends StatelessWidget {
final IconData icon;
final String label;
const NavBarItem({
super.key,
required this.icon,
required this.label,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(icon),
const SizedBox(height: 4),
Text(label),
],
),
);
}
}
Tomorrow, we'll explore more layout widgets including ListView, GridView, and SingleChildScrollView!
Learn about Flutter's widget tree structure and how to create stateless widgets to build the foundation of your Flutter applications.
Start Previous DayLearn about Flutter's advanced layout widgets including ListView, GridView, and SingleChildScrollView to create scrollable and grid-based user interfaces.
Start Next Day