Space, boxes, and cards
Learning objectives
- You know how to define areas around widgets and know how to reserve space for widgets.
- You know how to group content together and work with cards.
Component space
The space available for a widget and hence the size of the widget is in part determined based on both the widget and the widgets above the widget in the widget hierarchy. As an example, both Row and Column seek to minimize the area available for their children, unless explicitly defined (e.g. by a child widget).
The following example outlines this behavior. The application has two Text
widgets and a Container
with blue color. When you try out the application, you notice that the blue color is not visible.
This is similar to what we observed previously when working with Container
. We can influence the behavior by setting values to the width
and height
properties of the container; in such a case, the container is not minimized.
The example below would show a small blue area between the texts.
Let's look at the area available for widgets in another program. In the following example, we seek to show a blue container, a text, and a blue container.
When we launch the above example, the application shows an area with the message right overflowed
and prints information about an exception to the console.
Influencing available space
Flutter provides a handful of Layout widgets that can be used to define how widgets are shown. Two useful widgets include the Expanded widget that can be used to expand a child of a Container, Column, or Row, and the SizedBox widget that can be used to reserve a specified area for a widget.
The Expanded widget should feel somewhat familiar.
Expanded
The Expanded
widget has a child
property that is given a widget that should take the remaining available space. It can be used for both fitting a widget into the available space as well as to fill a remaining space.
The following example demonstrates using Expanded
to fit a widget into the available space. This fixes an overflow exception that we observed in the previous example -- now, instead of the text being rendered offscreen, the text is wrapped in the available space.
Similarly, we previously saw an example where a Column that contained a Container led to the Container being not visible at all. Using Expanded
, the Container fills the available space, as running the next example demonstrates.
If the program has multiple Expanded widgets in the same Column widget, the available space is divided equally between the widgets. The example below would create two equal sized containers, where one of them would be blue and one of them yellow.
SizedBox
The SizedBox widget is used to restrict the available space for the widget within the SizedBox widget. The space is defined using the width
and height
properties, while the child widget is defined using the child
property.
The following example demonstrates a program that has a 50
pixels wide red area and a blue area that takes up all the remaining space.
The following example builds on top of the above program by dividing the area on the right into two parts. On the upper right corner is an area that is 25 pixels high, while the remaining area is given to the color blue. As you notice, the available blue space is defined based on the screen size.
The above program is already relatively complex due to the quantity of widgets. It uses both rows and columns, as well as containers, and the size of the containers is influenced using the SizedBox and Expanded widgets. When we consider the program as a tree of widgets, the program could be represented as follows.
Padding
Previously, when learning to use containers, we briefly looked into setting padding
and margin
of a Container
. At that point, we used the EdgeInsets class to define offsets; e.g. calling EdgeInsets.all(16)
would be used to create a 16-pixel offset on all sides.
The Padding widget offers an explicit way for defining padding -- an area outside the widget -- for a widget. This leaves room "to breathe" and can create a more aesthetic feeling into the user interface.
The following example demonstrates the use of the Padding widget. In the example, a Text
widget within an Expanded
widget has been wrapped with a Padding
using 12 pixels on all sides.
With padding, be it in use in containers or separately, one could, for example, start building different kinds of layout widgets such as cards (which Flutter also directly provides). The following example shows a card with title and body and three icons (icon options available at Icons documentation); the example also uses the BoxDecoration class for decorating the container -- here, we simply set the background and round the borders using BorderRadius.
Cards
As mentioned briefly, Flutter provides also ready-made Card widgets that effectively provide styles for content. We'll take a peek at these next.
Grouping contents
The previously created widget SampleCard
is effectively a widget that is used to group things together. There are also ready-made widgets such as ListTile for grouping content such as title and subtitle, perhaps with some leading or trailing content. ListTiles are used in a ListView
or in a Column
, both of which we have learned to use before.
The following example shows an example use for ListTile
, where it is being used to display contacts.
ListTile
widgets are commonly used with Card widgets, which provides easy styling for the ListTile
. Card
is a single widget container, which is given a widget to style with the child
property. The following example shows the previous two contacts styled using Card
widget.
The property leading
sets an icon or an image to the left hand side of the ListTile
. If we would wish to place an icon on the right hand side, we would use the trailing
property. These properties can be, for example, used to highlight messaging, as shown in the following example. In the following example, we use CircleAvatar to create an icon that represents chat participants.