Building Twitter layout with Flutter
Tags: flutter, dev, mobile
Published: 2019-01-13 18:30:34

---
title: Building Twitter layout with Flutter
published: true
description: Using the infinite possibilities in Flutter to build the layout of your favorite app
tags: flutter, dev, mobile
---

Flutter is the new shiny framework for mobile development by Google, it was first released last year and this month it reached the 1.0 version. I've known Flutter for some months now, but since it reached 1.0 I decided to take a deeper look at it. I've developed mobile applications before using native Android with Java and cross-platform with Xamarim and NativeScript, it was not anything serious, but it is an area I find interesting and some people can argue, it is the near future. 

Presentations done, now let's go to the juicy details. In my opinion, the most remarkable feature of Flutter is how easy it is to understand its layouts mechanics. Basically, everything is a widget and you can put a widget anywhere you want. The widgets are very descriptive, have attributes that cover almost all common usages, it is effortless and simple to build a layout. Since everything is a widget, the framework is very permissive, dynamic and logical, you have no fear of doing something wrong, just do it, and with hot reload as fast a blink you can test everything easily. 

My experience with Flutter is amateur level, I did the most basic tutorial on [Flutter website](https://flutter.io), read some things about how Flutter handles layouts, principally [this great article](https://flutter.io/docs/development/ui/layout) that summarizes everything you need to know about Flutter layout structure. I would never dare to try replicate Twitter layout in none of the aforementioned frameworks, but with Flutter I had enough confidence to do it because I had no fear of failure. 

So we have something like this:

![Twitter layout](https://thepracticaldev.s3.amazonaws.com/i/bfokh6aufn6kj23f8a40.jpg)

To make it simpler, I made the layout taking in consideration only simple tweets, meaning only with text, no images, quotes, etc. Just to start. However, the rest will be present, the app bar at the top, the floating button to tweet and the bottom bar with tabs. Does it look too complex? Divide and conquer is the best approach for that! 

First, let's see the app bar at the top. We can see that we have a circle avatar and a text written "Home". An app bar is a very common design pattern in Android apps and Flutter knows that,because of that Flutter has widgets to make it easy to build one. To do that we use the `Scaffold` widget that has a parameter called `appBar` that accepts an `AppBar` widget as follows:

```dart
return MaterialApp(
      title: "Twitter Layout",
      theme: new ThemeData(
        primaryColor: Color.fromRGBO(21, 32, 43, 1.0),
        accentColor: Colors.blueAccent[200],
      ),
      home: new Scaffold(
          appBar: new AppBar(
            title: Row(
              children: <Widget>[
                Container(
                  child: CircleAvatar(
                    child: new Text("L"),
                    radius: 15.0,
                  ),
                  margin: EdgeInsets.only(right: 30.0),
                ),
                new Text("Home")
              ],
            ),
            elevation: 4.0,
          ),
          body: _buildBody(context)
      ),
    );
```
As you can see, the `Scaffold` widget is wrapped by a `MaterialApp` widget that makes is it easy to build apps using [Material Design](https://material.io), design directives for Android apps by Google, which the Twitter app clearly uses. The `AppBar` widgets has a `title` parameter that accepts any widget, although generally it is just a `Text` widget. Therefore, I created a `Row` widget that is responsible to place its children aligned horizontally, the way we want in this case. We add the children of the `Row` widget in a `children` parameter. In this case the widget has a `Container` and ` Text` as children. The `Container` widget is a very convenient widget because it enables you to custom spacing, positioning and painting configurations to its child. In this case, I added a `CircleAvatar` widget as its child and added a margin of 30 pixels to the right of the circle to give separation from the "Home" text. The child of a `CircleAvatar` widget can be any widget, but we generally use text or an image, to make it simple I used a `Text` with the letter "L". The radius indicates the size of the circle. If you notice, the circle on the app bar is a little smaller than the ones on the tweets, so I had to configure that. The `parameter` on the `AppBar` widget indicates the elevation of the app bar, it is what gives that shadow below it. In the end it was not necessary to make an app bar, a circular avatar and all the spacing configuration from the ground up, Flutter makes it easy to achieve the result you want with the use of common patterns. The `Scaffold` widget also has a `body` parameter, where, in this case, all the app content resides. Let's get into it. 

To organize the layout I made the body building logic on a `_buildBody()` method which is as follows: 

```dart
Widget _buildBody(context){
    return new Container(
      child: new Column(
        children: <Widget>[
          new Flexible(
              child: Scaffold(
                body: new ListView.builder(
                  itemBuilder: (_, int index) => _tweets[index],
                  itemCount: _tweets.length,
                  reverse: false,
                ),
                floatingActionButton: FloatingActionButton(
                    onPressed: null, child: Icon(Icons.edit)),
              )),
          new Container(
            decoration:
            new BoxDecoration(color: Theme.of(context).cardColor),
            child: _buildTabsBar(context),
          ),
        ],
      ),
    );
  }
```
The `_buildBody()` return a `Widget`, which is, in this case, a `Container`. The container has a `Column` widget as child, which all the magic happens. In the image used as base above we can see that we have the list of tweets and right below it the tabs bar, besides the floating button. The children of the `Column` widget are placed the way they appear on the screen. First, we have a `Flexible` widget and, as the names suggests, it is flexible, meaning in this case that it will occupy the remaining of the space of the parent, this is where our list and floating button are. The `Flexible` widget child is a `Scaffold` widget. Nobody said that it can be used only was the main widget of a an app like we used before although it is very common that way. It is used here to facilitate the creation of the floating button since it has a `floatingActionButton` attribute, which takes a `FloatingActionButton` widget with an edit icon as child. It also has an `onPressed` attribute to configure the event, but since the goal here is just to make the layout, it is `null` for now. Only this will make the floating button appear exactly where we want it. As before, on the `body` parameter of he `Scaffold` widget, we have the main content, the list of tweets, that is implemented using `ListView`, which is kind of a specialized column that enables scrolling when the content does not fit entirely in the widget. It simply builds the list from a list tweets, which we will see later. 

For now, let's focus on the other child of the `Column`, the container which has the method `_buildTabsBar()` as child. Let's see how the tabs are structured. 


```dart
Widget _buildTabsBar(context) {
    return Container(
      height: 60,
      color: Color.fromRGBO(21, 32, 43, 1.0),
      child: new Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          Icon(Icons.home, color: Theme.of(context).accentColor),
          Icon(Icons.search, color: Colors.grey[100]),
          Icon(Icons.notifications_none, color: Colors.grey[100]),
          Icon(Icons.mail_outline, color: Colors.grey[100])
        ],
      ),
    );
  }
```
Making the bar is very simple and that's what makes it fantastic. It is just a `Container` with a `Row` as child that has the icons as children, that's it. I configure the height of the container and its color. Then, in the `Row` I used the `mainAxisAlignment` attribute to make the space be evenly distributed between the icons making look like the original layout. I still remember how it is a pain to center things using HTML and CSS, not to mention make the space even.

So, let's see the last part, the tweet. It looks like the part where there are more elements to take care of and it is right, but it is not that much more complex than the rest of the layout if you visualize it as a collection of rows and columns. To make the tweet reusable and easy to use in a `ListView` I created a `Tweet` class containing all the layout for the tweet:

```dart
class Tweet extends StatelessWidget {

  Tweet({this.user, this.userHandle, this.text});

  final String user;
  final String userHandle;
  final String text;

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.all(10.0),
      decoration: BoxDecoration(
          color: Color.fromRGBO(21, 32, 43, 1.0),
          border: Border(bottom: BorderSide())),
      child: new Row(
        mainAxisAlignment: MainAxisAlignment.start,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          CircleAvatar(
            child: Text(user.substring(0, 1)),
          ),
          _tweetContent()
        ],
      ),
    );
  }

...

}
```
To make it simple, it is stateless and only gets the user, user handle and the tweet text to build the tweet. A full-fledged tweet would probably be statetul because of the counts for likes, retweets and answers and have much more parameters. The `build()` method returns a Container with the basic layout configuration, padding and a border at the bottom acting as a divider for the tweets, then it has a `Row` as child. The row contains the circle avatar of the user who tweeted and the tweet content, which is built through a method for organization sake. `mainAxisAlignment` and `crossAxisAlignment` set as `start` is very important because it makes the circle avatar to be placed at top-left corner as needed. 

The `_tweetContent()` method returns the content of the tweet, of course. Below is the entire method since it is easier to connect the dots by seeing all elements, after that I will explain the code. 

```dart
Widget _tweetContent(){
    return Flexible(
      child: Container(
        margin: EdgeInsets.only(left: 10.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            Row(
              children: <Widget>[
                Text(user,
                    style: TextStyle(
                        color: Colors.white,
                        fontWeight: FontWeight.bold)),
                Container(
                  margin: EdgeInsets.only(left: 5.0),
                  child: Text(userHandle + " · 30m",
                      style: TextStyle(color: Colors.grey[400])),
                )
              ],
            ),
            Container(
                margin: EdgeInsets.only(top: 5.0),
                child: Text(text, style: TextStyle(color: Colors.white))),
            Container(
              margin: EdgeInsets.only(top: 10.0),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: <Widget>[
                  Row(
                    children: <Widget>[
                      Icon(Icons.message, color: Colors.white),
                      Container(
                        margin: EdgeInsets.only(left: 3.0),
                        child: Text("15",
                            style: TextStyle(color: Colors.white)),
                      )
                    ],
                  ),
                  Row(
                    children: <Widget>[
                      Icon(Icons.repeat, color: Colors.white),
                      Container(
                        margin: EdgeInsets.only(left: 3.0),
                        child: Text("15",
                            style: TextStyle(color: Colors.white)),
                      )
                    ],
                  ),
                  Row(
                    children: <Widget>[
                      Icon(Icons.favorite_border, color: Colors.white),
                      Container(
                        margin: EdgeInsets.only(left: 3.0),
                        child: Text("15",
                            style: TextStyle(color: Colors.white)),
                      )
                    ],
                  ),
                  Icon(Icons.share, color: Colors.white)
                ],
              ),
            )
          ],
        ),
      ),
    );
  }
```

The parent element is a `Flexible` widget which allows the element to occupy the rest of the space available, the space on the row created on the `build` method above. Then we have a `Container` which allow to configure the margin necessary on the left of the content to separate it from the circle avatar. Finally, we have a `Column`, where the fun starts. 

Again we have `crossAxisAlignment` and `mainAxisAlignment` as `start` to make the content to be positioned a the top-left corner. The first child of the column is a `Row` that contains the user name, its handle and the time of the tweet. To make the user handle be slightly separated from the user name we wrap the `Text` into a `Container` as we've done before. The second child of the column is a `Container` that wraps the actual text of the tweet with a margin at the top. Finally, we have another container with a `Row` as child to build the reply, retweet, like and share buttons. `mainAxisAlignment` is set as `spaceBetween` so to that all icons will have an equal space between them and will be evenly distributed through the width of the row. Very convenient configuration, positioning and spacing was always something very troublesome for me in other frameworks. Each icon is a `Row` itself containing the icon and the number of replies, RTs, etc beside it. Simple, isn't it?  

So let's see the final result below:

![Twitter layout made with Flutter](https://thepracticaldev.s3.amazonaws.com/i/r3fppzy2rezs40yh6yv3.jpg)

It is close enough except for the icons which are probably Twitter exclusive. The tweets are just a sample. 

I hope this post will be of any use for people who are thinking about taking a look at Flutter and how to get started. For me it was love at the first sight when it comes to layout creation and unless it is limited about interactivity, where I still have to experiment, I believe that it will be popular very soon!