Flutter flexible widgets: Row
Flutter provides several layout widgets that help build UI easily. Let's explore how the Row widget can be used and configured to build our apps.
When building mobile applications you often have to work on the appearance and layout of your UI elements. Flutter provides a rich collection of layout Widgets that help make this process much simpler.
In this article, we will go through the essentials of the Row widget in Flutter and experiment with some of the common properties that can be used to configure this widget.
How does the Row widget work?
Row
is one of Flutter’s fundamental layout widgets, almost every app will use this widget. The Row widget arranges any children provided to it in a horizontal line.
By default, this widget always takes all available space in the horizontal direction. Without any fixed dimensions, Row will also resize itself based on the size of the screen, allowing you to build responsive layouts.
How to use the Row widget?
Let's look at a very basic usage of Row:
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Row(
children: [
SizedBox(
width: 100,
height: 100,
child: Container(
color: Colors.red,
),
),
SizedBox(
width: 100,
height: 100,
child: Container(
color: Colors.blue,
),
),
SizedBox(
width: 100,
height: 100,
child: Container(
color: Colors.green,
),
),
SizedBox(
width: 100,
height: 100,
child: Container(
color: Colors.purple,
),
),
],
),
),
),
);
}
In the code snippet above we have a very simple screen that renders 4 boxes horizontally, the output looks similar to this:
A simple row of boxes
In the example above we use Center
and Padding
for layout but by default, children are always laid out from the left, however Row
can be configured to change this.
Modifying horizontal alignment of the Row
First, let’s look at what the default Row
renders without the Padding
, we do not need to remove the Center
widget for this because it does not affect the horizontal layout of Row
.
The Row without the padding
The Row
widget accepts a property called mainAxisAlignment
which instructs the widget on how to align its children along the main axis. The main axis is the direction along which the widget renders its children, in the case of the Row
widget the main axis is horizontal.
You can use the following options for mainAxisAlignment
:
start
end
center
spaceAround
spaceBetween
spaceEvenly
start
, end
and center
simply align the children along the axis, start
being the left edge by default and end
being the right edge.
spaceAround
, spaceBetween
and spaceEvenly
align the children by applying spacing constraints to them.
Using MainAxisAlignment.start
This is the default alignment that Row
uses:
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
...,
],
),
),
);
}
The Row using MainAxisAlignment.start for layout
Using MainAxisAlignment.center
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
...,
],
),
),
);
}
The Row using MainAxisAlignment.center for layout
Using MainAxisAlignment.end
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
...,
],
),
),
);
}
The Row using MainAxisAlignment.end for layout
Using MainAxisAlignment.spaceAround
spaceAround
applies equal spacing to all children such that all children have equal spacing between them. The remaining space in the Row is then divided equally at the start and end of the Row.
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
...,
],
),
),
);
}
The Row using MainAxisAlignment.spaceAround for layout
Using MainAxisAlignment.spaceBetween
spaceAround
applies equal spacing to all children such that all children have equal spacing between them, but there is no spacing applied to the edges of the Row.
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
...,
],
),
),
);
}
The Row using MainAxisAlignment.spaceBetween for layout
Using MainAxisAlignment.spaceEvenly
spaceAround
applies equal spacing to all children such that all children have equal spacing between them and the same amount of spacing is applied to both start and end of the Row itself.
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
...,
],
),
),
);
}
The Row using MainAxisAlignment.spaceEvenly for layout
Modifying vertical alignment of the Row
Along with mainAxisAlignment
the widget also accepts a crossAxisAlignment
property. The cross axis is the secondary direction along which the widget renders its children, in the case of the Row
widget the cross axis is vertical.
You can use the following options for crossAxisAlignment
:
start
end
center
baseline
stretch
baseline
is a little more nuanced and will be skipped in this article.
Using CrossAxisAlignment.start
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
...,
],
),
),
);
}
The Row using CrossAxisAlignment.start for layout
Using CrossAxisAlignment.center
This is the default alignment that Row
uses:
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
...,
],
),
),
);
}
The Row using CrossAxisAlignment.center for layout
Using CrossAxisAlignment.end
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
...,
],
),
),
);
}
The Row using CrossAxisAlignment.end for layout
Using CrossAxisAlignment.stretch
stretch
forces all children of the Row to take the same height as the Row itself.
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
height: 300,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
...
],
),
),
),
);
}
The Row using CrossAxisAlignment.stretch for layout
stretch
also demonstrates the responsiveness properties of Row
. Because of its “flexible” nature, when there are no size constraints provided to Row
it takes all available space if its children also request unbounded sizes. When you use stretch
it tells its children to take up all available space, and without the Container
would result in all children taking the screen height because both the Row
and its children would request to take all available space.
Modifying how much space Row takes
Now that we know that Row
tries to make as much space as possible by default, we have identified one issue with building our layouts. In our example even though we use Center
the items in the Row are still laid out using the left edge of the screen.
The children are always laid out at the start of the Row
This is because the Row has an unbounded width constraint so it uses screen width and by default the alignment along the main axis is the start of the Row.
Row
accepts a property called mainAxisSize
which controls how much space it takes along the Main Axis (i.e horizontal). You can use the following values for mainAxisSize
:
min
max
Using MainAxisSize.min
min
instructs the widget to constrain its size along the main axis to be equal to the width constraint of its children (including any padding or spacing the children may have)
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
...
],
),
),
);
}
The Row is now rendered in the center of the screen
Because min
makes the Row
size according to its children, the layout constraints imposed by Center
start to work as expected.
Using MainAxisSize.max
This is the default size that Row
uses.
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Row(
mainAxisSize: MainAxisSize.max,
children: [
...
],
),
),
);
}
Row takes full-screen width
The Row widget is extremely useful when it comes to building mobile applications and with some basic configuration, you can use it to create great-looking UI really easily!