How to use Row and Column in Flutter with examples

Share this post

Row and Column might be the most important (multi-child) layout widgets in Flutter. Row and Column let you align child widgets horizontally and vertically. If you are a web developer, you can compare them with a div with the following properties in CSS:

.row {
 display: flex;
 flex-direction: row; // this is the default
}

.column {
 display: flex;
 flex-direction: column;
}

Use case: How to create a list item using Row widget in Flutter

I’m going to show you how to create a nice list item using a Row widget. This is a good example because in a list item the information is aligned horizontally. Let’s say we want to show a list of contacts like we have in WhatsApp and we want to define how each of these list items will look like. Let’s say we have the following requirements:

  • An Avatar
  • The name of our contact
  • List item must be clickable with some visual feedback
  • The widgets inside Row must be aligned nicely

First, we need an avatar for our contact. Flutter provides us with a very nice widget called CircleAvatar that gives you a ready-to-use circular widget specially made for this purpose. So we will use that one. We define a background color for our avatar and take the first letter of our contact instead of an image. For the name of our contact, we will be using the Text widget obviously.

Our widget structure will look like this:

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Row(
        children: <Widget>[
          CircleAvatar(
            backgroundColor: Colors.blue,
            child: Text(
              'J',
              style: TextStyle(
                fontWeight: FontWeight.bold,
                color: Colors.white,
              ),
            ),
          ),
          Text('John Doe'),
        ],
      ),
    );
  }

And will look like this on our device:

Alignment using Row widget

It does not look very great, but it’s a good start. First of all, our Row is too close to the left and the top. Somehow we need to add distance between the Row and the parent widget. We will use a Container for that with small padding.

The next thing we probably want to fix is the fact that the text and the avatar are too close to each other. We will put a SizedBox between them with the desired width.

Lastly, we wrap our Row inside an InkWell. InkWell provides us with GestureDetector (which gives us an onTap callback) plus visual feedback.

The improved code:

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: InkWell(
        child: Container(
          padding: EdgeInsets.all(16.0),
          child: Row(
            children: <Widget>[
              CircleAvatar(
                backgroundColor: Colors.blue,
                child: Text(
                  'J',
                  style: TextStyle(
                    fontWeight: FontWeight.bold,
                    color: Colors.white,
                  ),
                ),
              ),
              SizedBox(
                width: 16.0,
              ),
              Text('John Doe'),
            ],
          ),
        ),
        onTap: () {
          // do something here
        },
      ),
    );
  }

And will look like this on our device:

Alignment using Row widget

It looks much better now and it’s tappable. Of course, there are many more use cases where you would be using the Row widget, but the principle stays the same.

Alignment properties in Row and Column

Row and Column have the same alignment properties, they work for the mainAxisAlignment (horizontal in Row and vertical in Column) and crossAxisAlignment (the opposite of mainAxis). For example, if I want to define that child widgets should be aligned vertically within the Row widget, I would have to use the crossAxisAlignment, as I’m defining the alignment in the opposite direction. These 2 alignment categories can be set to one of the following values:

  • start
  • center
  • end
  • spaceAround: Place the free space evenly between the children as well as half of that space before and after the first and last child.
  • spaceBetween: Place the free space evenly between the children.
  • spaceEvenly: Place the free space evenly between the children as well as before and after the first and last child.

Let’s say we decide to use spaceBetween to align our avatar and text in the previous example. It will then look like this:

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: InkWell(
        child: Container(
          padding: EdgeInsets.all(16.0),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: <Widget>[
              CircleAvatar(
                backgroundColor: Colors.blue,
                child: Text(
                  'J',
                  style: TextStyle(
                    fontWeight: FontWeight.bold,
                    color: Colors.white,
                  ),
                ),
              ),
              SizedBox(
                width: 16.0,
              ),
              Text('John Doe'),
            ],
          ),
        ),
        onTap: () {
          // do something here
        },
      ),
    );
  }

Which will look like this:

MainAxisAlignment.spaceBetween

You can try the other properties yourself to see what happens (if you are a web developer, it works the same as flex properties.

Use case: How to create a login form using Column in Flutter

A very good example of when Column comes in handy is probably alignment of form widgets in a page. That’s because we want to align the widgets vertically aka in a Column.

Let’s create a login form containing a username and a password field. I’m not going too deep into technicalities, as I’m focusing on alignment for now. I will write a separate post about how to properly use a form in Flutter.

@override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Container(
        padding: EdgeInsets.all(16.0),
        child: Column(
          children: <Widget>[
            TextField(
              keyboardType: TextInputType.emailAddress,
              decoration: InputDecoration(
                hintText: "Your email address",
              ),
            ),
            SizedBox(
              height: 32,
            ),
            TextField(
              keyboardType: TextInputType.text,
              obscureText: true, // because it's a password
              decoration: InputDecoration(
                hintText: "Your password",
              ),
            ),
            SizedBox(
              height: 32,
            ),
            RaisedButton(
              child: Text("Login"),
              color: Colors.blue,
              textColor: Colors.white,
              onPressed: () {
                // perform login
              },
            ),
          ],
        ),
      ),
    );
  }

This will look like this:

This post explains the basic working of Row and Column which align their children in a horizontal and vertical way. There are more advanced alignments within Row and Column, like how much each child should occupy, which I will explain in a separate post.