Flutter flexible widgets: Row

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.

·

7 min read


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:

Simple row layout

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.

Row without padding

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: [
            ...,
          ],
        ),
      ),
    );
  }

Simple row with alignment start

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: [
            ...,
          ],
        ),
      ),
    );
  }

Simple row with layout center

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: [
            ...,
          ],
        ),
      ),
    );
  }

Simple row with layout end

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: [
            ...,
          ],
        ),
      ),
    );
  }

Simple row with layout space around

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: [
            ...,
          ],
        ),
      ),
    );
  }

Simple row with layout space between

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: [
            ...,
          ],
        ),
      ),
    );
  }

Simple row with layout space evenly

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: [
            ...,
          ],
        ),
      ),
    );
  }

Simple row with cross layout start

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: [
            ...,
          ],
        ),
      ),
    );
  }

Simple row with cross layout center

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: [
            ...,
          ],
        ),
      ),
    );
  }

Simple row with cross layout end

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: [
              ...
            ],
          ),
        ),
      ),
    );
  }

Simple row with cross layout stretch

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.

Children being rendered at the start of the row

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: [
            ...
          ],
        ),
      ),
    );
  }

Row sizes itself according to its 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 taking max possible size

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!