Flutter Container with challenges

Alfonso García Santiago
13 min readJan 7, 2021

--

In this story, you will find 4 challenges to try and some examples to learn about the Container widget. How to align, decorate, and compose containers.

Table of Contents

Challenges

Examples and theory

  • Definition
  • Basic use of a Container widget
  • Giving a width and a height and aligning its child
  • Center and Align widgets
    • Center widget
    • Align widget using a predefined value
    • Align widget using width and height factors
  • Decoration
    • Rounded corners
    • Rounded corners: Stadium shape
    • Rounded corners (only some of them)
    • Circular shape
    • Border
    • Shadow
    • Two-color Linear Gradient
    • Basic 2-color-linear-gradient with stops
  • Composing containers
    • The child widget has a height and width
    • The child widget has height but NO width
    • The child widget has NO height and NO width
    • The child widget has NO width but has constraints (margin)

NOTE: Both Transform widget and transform container-property will be covered in the next stories. Do not miss them!!

CHALLENGES

Enjoy the following challenges and take them seriously. They will boost your level !!

Remember, if you have problems or doubts to resolve the challenges, try first reading some theory and examples that you can find after them.

The challenge

You are challenged to create a design similar to a Landing Helicopter Zone (screenshot below).

You do not need to:

  • use the same color or the same font size as I have used

You should:

  • align the design to topCenter of the screen
  • set a top-margin to separate it from the AppBar
  • align the text ‘H’ to the center of the parent container
  • use only instances of Align, Container, and Text widgets, and their properties

And now, stop reading and try to do it by yourself before seeing my solution.

Good luck!

My solution

This is not the only possible solution; it is just my solution…

Align(
alignment: Alignment.topCenter,
child: Container(
margin: EdgeInsets.only(top: 20),
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: Colors.orange,
width: 10,
),
),
width: 280,
height: 280,
alignment: Alignment.center,
child: Text(
'H',
style: TextStyle(
fontSize: 180,
color: Colors.orange,
),
),
),
)

The challenge

Try creating this design as similar as it is possible.

You do not need to:

  • use the same background color or the same font size, or the same border-radius as I have used

You should:

  • use only instances of Container and Text widgets and their properties

And now, stop reading and try to do it by yourself before seeing my solution.

Good luck!

My solution

This is not the only possible solution; it is just my solution…

Container(
height: 130,
width: double.infinity,
decoration: BoxDecoration(
color: Color(0xFF57B3FC),
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(50),
bottomLeft: Radius.circular(50),
),
boxShadow: [
BoxShadow
(
color: Color(0xAA6EB1E6),
offset: Offset(9, 9),
blurRadius: 6,
),
],
),
alignment: Alignment.center,
child: Text(
'I am a header',
style: TextStyle(
fontSize: 38,
color: Colors.white,
),
),
)

The challenge

Try creating the design below as similar as it is possible.

You do not need to:

  • use the same colors or the same size or the same border-radius as I have used

You should:

  • use only instances of Container widget and its properties

And now, stop reading and try to do it by yourself before seeing my solution.

Good luck!

My solution

This is not the only possible solution; it is just my solution…

Container(
margin: EdgeInsets.all(40),
width: 300,
height: 90,
alignment: Alignment.centerLeft,
decoration: BoxDecoration(
color: Color(0xFF4AAEFD), //blue
borderRadius: BorderRadius.circular(45),
),
child: Container(
width: 210,
height: 90,
decoration: BoxDecoration(
color: Color(0xFF94CCF9), //light blue
borderRadius: BorderRadius.only(
topLeft: Radius.circular(45),
bottomLeft: Radius.circular(45),
),
),
alignment: Alignment.center,
child: Text(
'Challenge',
style: TextStyle(
fontSize: 32,
color: Colors.white,
),
),
),
)

To get a stadium-shape effect, we use a big enough value as border-radius. Greater or equal than half the height.

As the container widget is a single-child layout widget, it can only have one child. So the key is to create the blue container and then create the light-blue container as a blue container’s child. Finally, we will create the text widget as a child of this last light-blue widget.

The challenge

Try to achieve the design below.

You do not need to:

  • use the same colors or the same size or the same border-radius as I have used

You should:

  • use only instances of Container and Text widgets and their properties
  • align the orange container to the top-center of the screen
  • do the orange container as wider as possible by leaving a margin around it

Please, pay attention:

  • The orange container has a fine left-bottom-oriented shadow.

And now, stop reading and try to do it by yourself before seeing my solution.

Good luck!

My solution

This is not the only possible solution; it is just my solution…

First, we create a parent container, which gives us the color background that fills the screen.

class Challenge extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
color: Color(0xFF272A3C),
width: double.infinity,
height: double.infinity,
alignment: Alignment.topCenter, //to align its child
child: CardContainer(),
);
}
}

And we write the code for our custom container called CardContainer:

class CardContainer extends StatelessWidget {

@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(30),
height: 160,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
gradient: new LinearGradient(
colors: [
Color(0xFFFF422C),
Color(0xFFFF9003),
],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
stops: [0.25, 0.90],
),
boxShadow: [
BoxShadow(
color: Color(0xFF101012),
offset: Offset(-12, 12),
blurRadius: 8,
),
],
),
alignment: Alignment.centerLeft, //to align its child
padding: EdgeInsets.all(20),
child: Text(
'Challenge',
style: TextStyle(
fontSize: 46,
color: Colors.white,
fontWeight: FontWeight.w200,
fontStyle: FontStyle.italic,
),
),
);
}
}

Have you taken your time to try these challenges? If so, congratulations! That’s the way!

Read the following theory and examples to get background and ideas to help you solve the previous challenges.

EXAMPLES AND THEORY

Definition

Container widget is a useful widget when it comes to layout tasks. We may use it to decorate (adding some background styling), compose, and position a child widget.

It is a single-child layout widget (it only has one child).

Basic use of a Container

First, we use only a Text widget…

Text(
'I am a text',
style: TextStyle(
fontSize: 38,
color: Color(0xFF04589A),
),
)

Let’s wrap the Text widget in a Container widget with no color or decoration and see how there is no difference from the previous example. Only Text is visible.

Container(
child: Text(
'I am a text',
style: TextStyle(
fontSize: 38,
color: Color(0xFF04589A),
),
),
)

Adding color to the Container:

Container(
color: Color(0xFF94CCF9),
child: Text(
'I am a text',
style: TextStyle(fontSize: 38, color: Color(0xFF04589A)),
),
)

Let’s add some margin to separate the container from the top-left corner and some padding to separate the text from the container border.

Container(
color: Color(0xFF94CCF9),
padding: const EdgeInsets.all(20),
margin: const EdgeInsets.only(left: 40, top: 40),
child: Text(
'I am a text',
style: TextStyle(fontSize: 38, color: Color(0xFF04589A)),
),
)

Giving a width and a height, and aligning its child

A container first surrounds the child with padding (inflated by any borders present in the decoration) and then applies additional constraints to the padded extent (incorporating the width and height as constraints, if either is non-null). The container is then surrounded by additional empty space described from the margin.

So if we don’t set the container's width and height, this will be as small as possible, wrapping the child with padding.

But if we define the container’s width and height, the container will honor these dimensions. And the child will be aligned inside the container to the top-left corner by default, as you can see in the following example:

Container(
color: Color(0xFF94CCF9),
padding: const EdgeInsets.all(15),
margin: const EdgeInsets.only(left: 40, top: 40),
width: 250,
height: 250,
child: Text(
'Text',
style: TextStyle(fontSize: 32, color: Color(0xFF04589A)),
),
)

We can change the child’s alignment inside the container (alignment property).

Container(
color: Color(0xFF94CCF9),
padding: const EdgeInsets.all(15),
margin: const EdgeInsets.only(left: 40, top: 40),
width: 250,
height: 250,
alignment: Alignment.bottomRight,
child: Text(
'Text',
style: TextStyle(fontSize: 32, color: Color(0xFF04589A)),
),
)

Center and Align widgets

We can center or align our container in its parent by wrapping it with two new widgets: Center and Align.

Center widget

Center(
child: Container(
color: Color(0xFF94CCF9),
padding: const EdgeInsets.all(15),
child: Text(
'I am a text',
style: TextStyle(
fontSize: 38,
color: Color(0xFF04589A),
),
),
),
)

Align widget using a predefined value

Aligning using a predefined value like:

  • topLeft
  • topCenter
  • topRight
  • centerLeft
  • center
  • centerRight
  • bottomLeft
  • bottomCenter
  • bottomRight
Align(
alignment: Alignment.bottomLeft, //Alignment(-1.0, 1.0)
child: Container(
....
),
)

Align widget using width and height factors

Aligning to a concrete position inside the parent widget using double values for widthFactor and heightFactor in the constructor.

Both factors, in their corresponding dimensions, go from -1.0 value to 1.0 value.

For example, when it comes towidthFactor : -1.0 is the left border, 0.0 is the center, and 1.0 is the right border. Going further, -0.5 means the point in the middle between the left border and the center…

Align(
alignment: Alignment(-0.5, 0.75),
child: Container(
....
),
)

Decoration

Another thing we can do with a container is decorating. We will use the decoration property for it.

There are several options to choose adecoration value:

  • BoxDecoration
  • FlutterLogoDecoration
  • ShapeDecoration
  • UnderlineTabIndicator

Here we will use the BoxDecoration class to do it.

BoxDecoration is an immutable description of how to paint a box and provides a variety of ways to draw a box.

We can choose a color background, an image background, a shape, a border, a corner shape (borderRadius), a shadow, and a gradient.

This is not an exhaustive description of using these properties but only giving some examples of usage.

If we use the decoration property in a container then the container’s color property must be inside the decoration class.

Rounded corners

We will indicate rounded corners by using the boderRadius property of the BoxDecoration.

Container(
margin: EdgeInsets.all(40),
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Color(0xFF9DF09E),
borderRadius: BorderRadius.circular(20),
),
child: Text(
'I am a text',
style: TextStyle(
fontSize: 38,
color: Color(0xFF1F9221),
),
),
)

Rounded corners: Stadium shape

We say “stadium shape” when the border-radius is big enough to achieve a completed-vertical rounded shape on every side (left and right).

We can get it giving a big value as border-radius.

Container(
margin: EdgeInsets.all(40),
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Color(0xFFF8DAA0),
borderRadius: BorderRadius.circular(500),
),
child: Text(
'I am a text',
style: TextStyle(
fontSize: 38,
color: Color(0xFFEC9B02),
),
),
)

Rounded corners (only some of them)

Container(
margin: EdgeInsets.all(40),
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.purple,
borderRadius: BorderRadius.only(
topRight: Radius.circular(40.0),
bottomLeft: Radius.circular(40.0)
,
),
),
child: Text(
'I am a text',
style: TextStyle(
fontSize: 38,
color: Colors.white,
),
),
)

Circular shape

We will use a BoxShape for the shape property.

Container(
margin: EdgeInsets.all(30),
decoration: BoxDecoration(
color: Colors.purpleAccent,
shape: BoxShape.circle,
),
width: 150,
height: 150,
)

Border

Container(
margin: EdgeInsets.all(40),
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Color(0xFF94CCF9),
border: Border.all(
color: Color(0xFF04589A),
width: 4,
),
borderRadius: BorderRadius.circular(10.0),
),
child: Text(
'I am a text',
style: TextStyle(
fontSize: 38,
color: Color(0xFF04589A),
),
),
)

Shadow

Container(
margin: EdgeInsets.all(40),
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Color(0xFF94CCF9),
borderRadius: BorderRadius.circular(30.0),
boxShadow: [
BoxShadow(
color: Color(0xFF04589A),
offset: Offset(7, 7),
blurRadius: 6,
),
],
),
child: Text(
'I am a text',
style: TextStyle(
fontSize: 38,
color: Color(0xFF04589A),
),
),
)

We set a shadow effect by using the boxShadow property. Inside the BoxShadow, we use the offset property to tell the displacement of the shadow. And we can add blur to get a more realistic effect.

The previous screenshot shows a too strong shadow (color 0xFF04589A).

If we reduce the opacity a little, for example, from value 0xFF04589A to 0x9904589A, we get a better result. Let’s see!

Two-color Linear Gradient

Container(
margin: EdgeInsets.all(40),
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Color(0xFF94CCF9),
border: Border.all(
color: Color(0xFF04589A),
width: 4,
),
borderRadius: BorderRadius.circular(10.0),
gradient: LinearGradient(
colors: [Colors.white, Color(0xFF75C0FC)],
begin: Alignment.centerLeft,
end: Alignment.centerRight),
),
child: Text(
'I am a text',
style: TextStyle(fontSize: 38, color: Color(0xFF04589A)),
),
)

Two-color Linear Gradient with stops

Gradient stops are alist of values from 0.0 to 1.0 that denote fractions along the gradient.

In the previous example, we did not use stops. This is the same as using the stops [0.0, 1.0].

What about using different stop values? Let’s see a few examples!

To give more importance to the left color (white), we provide a value greater than 0.0 to the first stop:

Container(
margin: EdgeInsets.all(40),
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Color(0xFF94CCF9),
border: Border.all(
color: Color(0xFF04589A),
width: 4,
),
borderRadius: BorderRadius.circular(10.0),
gradient: LinearGradient(
colors: [Colors.white, Color(0xFF75C0FC)],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
stops: [0.4, 1.0],
),
),
child: Text(
'I am a text',
style: TextStyle(fontSize: 38, color: Color(0xFF04589A)),
),
)

To achieve the opposite effect, I mean, seeing more blue (right color) than white (left color), we choose a value lower than 1.0 to the second stop [0.0, 0.6]:

In the following example, we can see a beautiful linear-gradient filling the screen:

Center(
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomLeft,
end: Alignment.topRight,
colors: [
Color(0xFFFBA3660),
Color(0xFF1C256E),
],
stops: [0.3, 0.75],
),
),
),
)

Composing Containers

Composing containers is setting a container inside another container, or in other words, setting a container as a child of another container.

The child widget has a height and width

Container(
margin: const EdgeInsets.all(30),
decoration: BoxDecoration(
color: Colors.purple,
borderRadius: BorderRadius.circular(10.0),
),
width: 250,
height: 250,
alignment: Alignment.bottomCenter,
child: Container(
decoration: BoxDecoration(
color: Colors.cyan,
borderRadius: BorderRadius.circular(10.0),
),
height: 100,
width: 150,
),
)

The cyan container has been declared as a child of the purple container.

The child widget is aligned to the parent bottom-center (alignment property in the parent widget).

The child widget has height but NO width

Container(
margin: const EdgeInsets.all(30),
decoration: BoxDecoration(
color: Colors.purple,
borderRadius: BorderRadius.circular(10.0),
),
width: 250,
height: 250,
alignment: Alignment.bottomCenter,
child: Container(
decoration: BoxDecoration(
color: Colors.cyan,
borderRadius: BorderRadius.circular(10.0),
),
height: 100,
),
)

We have set the child’s height but have not set the child’s width. However, the child widget (cyan) covers the parent’s width completely.

If the Container widget has no child, no height, no width, no constraints, and no alignment, but the parent provides bounded constraints, then Container expands to fit the constraints provided by the parent.

Taking this into account, we can explain better the cyan-widget behavior in the previous screenshot:

  • The cyan widget has no child and has no width, and the parent, the purple container, provides bounded constraints. Our child cyan container fills the parent’s horizontal dimension because it has no width.

The child widget has NO height and NO width

Container(
margin: const EdgeInsets.all(30),
decoration: BoxDecoration(
color: Colors.purple,
borderRadius: BorderRadius.circular(10.0),
),
width: 250,
height: 250,
alignment: Alignment.bottomCenter,
child: Container(
decoration: BoxDecoration(
color: Colors.cyan,
borderRadius: BorderRadius.circular(10.0),
),
),
)

In this case, the child widget covers the parent’s width and height completely, so the parent widget (purple widget) is hidden by the child widget (cyan widget).

Child widget has NO width but has constraints (margin)

Container(
margin: const EdgeInsets.all(30),
decoration: BoxDecoration(
color: Colors.purple,
borderRadius: BorderRadius.circular(20.0),
),
width: 250,
height: 250,
alignment: Alignment.bottomCenter,
child: Container(
margin: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.cyan,
borderRadius: BorderRadius.circular(20.0),
),
height: 100,
),
)

The child widget does not completely cover the parent’s width because we have defined a 10-dip margin in the child widget.

NOTE: Both Transform widget and transform container-property will be covered in the next stories. Do not miss them!!

If you have found this article enjoyable or it has helped you in some way, give me many 👏.Thanks for reading me!

--

--