Flutter Container with challenges
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
, andText
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
andText
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
andText
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
andheight
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
, nowidth
, 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!