Common Layout Widgets
Learning Objectives
- You know of common layout widgets in Flutter.
- You can use the Container, Row, Column, and Scaffold widgets.
- You are aware of Flutter making use of its layout algorithm to determine the size of widgets.
Flutter comes with a large API that makes building applications easier. Here, we look at a handful of layout widgets that are commonly used in Flutter applications. We start by looking at the Container widget, which is a basic building block for layouts. We then look at the Row and Column widgets, which are used to place widgets in horizontal and vertical arrays. Finally, we look at the Scaffold widget, which is a basic building block for layouts.
Container
Container allows defining an area that can be adjusted through a set of properties. The size of a container can be set using width
and height
, and the space around and within the border of the container with margin
and padding
. The color of the area is set using color
(using a constant from the class Colors). A widget, if any, that the container contains, is set using child
.
The following example demonstrates the use of the container widget. In the example, we create a container with width 200
, height 100
, color blue ), and the text “Hello world!”. By default, the contents of a container are aligned to the left upper corner.
The properties margin
and padding
are used to specify outside and inside borders of the area of a container. The property margin
defines an area outside the container border, while the property padding
defines an area within the container border. The values of margin
and padding
are defined using EdgeInsets class. The named constructor EdgeInsets.all
allows creating offsets to all sides of the a container (i.e. left, right, top, bottom).
The following example demonstrates the above program with margin
set to 30 pixels and padding
set to 10 pixels. In practice, this means that the area outside the container is 30 pixels wide, while the text within the container has a 10 pixel distance from the container border.
The following example shows the program with a red container inside the blue container instead of a text. When you run the program, you’ll notice the effect of padding — the value given to padding
effectively creates the blue border for the red container.
Try changing the above example so that the value given to padding
is 0
. You will notice that the blue color is no longer visible.
Container layout behavior
The container widget uses a layout algorithm to determine the size of the container. As outlined in Container documentation, “Container tries, in order: to honor alignment, to size itself to the child, to honor the width, height, and constraints, to expand to fit the parent, to be as small as possible.”.
Let’s look at sizing of containers in detail.
Honoring alignment
The alignment
property is used to define how a child widget is positioned within the container. The value of alignment
is an instance of an AlignmentGeometry, typically set using constants from the class Alignment.
The following example demonstrates the use of the alignment
property for centering the text widget within the container.
When you run the above program, you notice that the container expands to fill the screen and the text is centered on the screen.
Sizing to a child
If a container has a child widget, the container matches its size to the size of the child widget (given that the size of the container is not defined). In the following example, a blue container has a text widget child. As we observe, the container sizes itself to the child.
However, as we observed before, if the container has an alignment, the container expands to fit the parent and uses the alignment to position the child.
Note that this holds when the parent widget has a defined size (e.g. the screen). There are also widgets with so-called unbounded size. We will look into some of these a bit later.
Honoring size
If a container is given explicit size using width
and height
, the layout attempts to respect the given size. In the following example, the width of the container is 200 pixels and the height of the container is 100 pixels.
On the other hand, if only width
is defined, the height
of the widget is defined by following the previous rules: (1) honoring alignment and (2) sizing to a child. As an example, the height of the blue container in the following example will be sized to match the text widget within the container.
If we add an alignment — say Alignment.center
to the above example, we notice that the height of the container will be expanded to match the whole screen.
Expanding to fit the parent
A container tries to expand to fit the size of the parent if it has no alignment, size, or child. In the following example, a container with a width and height contains another container that does not have alignment, size, or a child. When you try out the program, you notice that the blue container is not visible at all. This happens because the red container expands to fit the parent, and the available area is inherited from the outer container.
The available space naturally depends on how the parent container is defined, and constraints are respected. For example, if the blue container has a padding, the red container fills all the area available within the constraints of the padding.
Container in a tree of widgets
In practice, when determining the size of a container, Flutter’s layout algorithm traverses the tree of widgets downwards to find a widget with a size, which it then propagates upwards. If there is no widget with a size, the container expands to fit the parent.
The following example outlines three nested containers, where the innermost container contains a text widget. The containers do not have an alignment or a size, with the exception of the padding. Because the innermost container has a widget with a size, the container is sized to the child. Now, as the innermost container has a padding, the padding is added to the size of the container which is then propagated upwards in the tree of widgets to the next container, and so on.
In the following example, we have the same three nested containers where the insidemost container has a text widget. In this case, the outermost container has the alignment
property set to Alignment.center
. Now, as the container has an alignment, the container expands to fit the parent, and the alignment is used to position the child widget.
In the above example, the layout algorithm traverses the tree of widgets downwards to find a widget with a size; the text widget passes its size to the green widget, which passes the size to the red widget, which passes it upwards. Now, the blue widget has been created so that its’ contents are centered, and thus the red widget (and its contents) are centered in the blue widget. As there are no constraints on the size of the blue widget from the children, the blue widget expands to fill the screen.
Rows and Columns
Row and Column widgets allow placing widgets in horizontal and vertical arrays. The Child widgets are given to row and column with the children
property, which receives a list of widgets.
By default, both Row and Column minimize the space that the widgets within them have available. To adjust the behavior, we can use the Expanded widget that is used to expand the child of a row (or column) to fill the potentially available space.
The following demonstrates the use of Row for showing three containers, each with their own color. Each container is placed within an expanded widget. When you run the program, you notice that the containers are shown side by side, each taking up an equal amount of space.
We can also define the size of a specific container and have the others as expanded. In the following example, the leftmost container is always 40 pixels wide, while the other containers divide the remaining space between them.
The Column widget behaves similarly to the row widget. Column is used to create a series of widgets that are shown vertically. Similarly to Row, the Column has a property widgets
that is given a list of widgets as a value. The following example demonstrates the use of Column for showing three containers, each with their own color. Each container is placed within an expanded widget. When you run the program, you notice that the containers are shown on top of each other, each taking up an equal amount of space.
Similar to the earlier example, we can also define the size of a specific container and have the others as expanded. In the following example, the container at the bottom has a height of 40 pixels, while the other containers divide the remaining space between them.
Rows and columns can also be used together. In the following example, a column contains a container and a row. The container contains a text widget, while the row contains three expanded text widgets. In effect, the example is used to show a question and three answer options, where the question is at the top and the answer options are side by side in a row.
Scaffold
The Scaffold is a basic building block for layouts. It has a handful of properties which allow setting common elements in applications, including the following:
- The property appBar allows setting an instance of a PreferredSizeWidget such as AppBar to the top of the application.
- The property body allows defining the body of the application.
- The property bottomNavigationBar allows setting a widget at the bottom of the application.
- The property drawer allows creating a drawer (a panel) to the side of the application.
- The property floatingActionButton allows placing a widget, often an instance of a FloatingActionButton, to the bottom right corner of the application.
The following example uses all of the above properties.