Leave a rating/review
The rest of this course would focus on building a news reader app. In this episode, we’ll combine what we’ve learnt so far to build an article card widget. I’ve cleared out the previous code in the MainPage
widget and the body currently returns an ArticleCard
widget.
Open up the widget’s definition clicking on it and pressing the F12
key to go to its definition. This file is contained inside the widgets folder. This folder would contain custom widgets that can be used in multiple places.
The ArticleCard
is a StatelessWidget
that curently returns an empty Container
. This widget would be used to display an individual Article
. For this, i have created a model and some dummy data.
Head over to article.dart
inside the models folder. Here you can see the Article
class with its members. Below it, you have List
of Articles. We would be using the articles
variable to access the data.
Close the file and head back to the ArticleCard
widget. Add the article property:
...
final Article article;
const ArticleCard({
Key? key,
required this.article,
}) : super(key: key);
...
This exposes the article member in the constructor as a named parameter so we can pass an article when using this widget. We also added the required
keyword to make sure we pass an article to the card.
Head over to main_page.dart
. And you can see it currently complains that it expects a required argument. Go ahead and pass a single article from the articles List. And make sure you remove the const keyword because this class is no longer a constant value.
ArticleCard(article: articles[0])
This passes the first index from the articles list to the named parameter called article. Save this file and head back to the article card class.
Okay, replace the Container
with the following code:
...
return Card(
margin: const EdgeInsets.all(16),
elevation: 4,
child: Column(
children: <Widget>[
CardBanner(),
CardDetail(),
]
),
);
...
First we return a Card
widget with a margin
of 16 and an elevation
of 4. The elevation
is used to create depth by adding a shadow around the Card. The Card has a Column
as its child. The Column
would have an banner and a Detail region below it.
Let’s create the CardDetail
widget. Comment the CardBanner()
widget and then paste the following code below ArticleCard
class:
class CardDetail extends StatelessWidget {
final Article? article;
const CardDetail({Key? key, this.article}) : super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
article!.title,
style: const TextStyle(fontSize: 24),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 16),
Row(
children: <Widget>[
Text(article!.source),
const Spacer(),
const Text('45 Comments'),
],
)
],
),
);
}
}
Update the call to this widget by passing in the article argument like so:
...
CardDetail(article: article),
...
Save you work. I noticed that the UI doesnt show up. This could be a sign that we have an error. Go ahead and open up the debug console.
And you can see that we need to do a hot restart. Go ahead and do that now. And you can see, the UI displays as expected. Now, you should be familiar with this type of code but I’ll explain some little additions to it.
This creates a widget that accepts an article as an argument. It returns a Padding
with a padding
of 16. A padding is used instead of a Container here because we only want to add a padding. It’s child is a Column
with a title text, a SizedBox
and a Row
. The text is given a maxLine of 2 which limits the text to span 2 lines. If the text is longer than two lines, the overflow would be represented by an ellipsis.
Next is the SizedBox
with a height of 16. This widget is an empty box used to add a fixed spacing between the top and bottom children of the column.
Finally we have the Row
. It has three children. The first is the source text and the last child is the comments text.
In between them is a Spacer()
widget. This widget adds an empty space between flex widgets. Currently, it takes all the available space in between the other two children.
And by the way, Column
and Row
are examples of flex widgets. An alternative to achieving the same effect would be remove the Spacer
and wrap the first child of the Row with an Expanded
widget.
And if you notice, this card currently stretches from the top to the bottom of the available space. To correct this, head over to the MainPage
widget and place the ArticleCard widget inside a Column. And this corrects it by limiting the height of the card to its content.
Let’s head by to the ArticleCard
class and create the CardBanner
. This widget would display an image. First, uncomment it where it is called inside the ArticleCard
widget.
Then scroll down and enter the following code:
class CardBanner extends StatelessWidget {
final String? imageUrl;
const CardBanner({Key? key, this.imageUrl}) : super(key: key);
@override
Widget build(BuildContext context) {
return const Placeholder(fallbackHeight: 200);
}
}
Save your work and you should see the changes. We intend returning an image but since we’re not yet ready to code it up, a Placholder
widget is returned with the expected dimensions. Then whenever we want to add the image, we’ll just replace this widget with an image and be rest assured that our UI won’t break. A very handed widget indeed.
Finally, let’s add a bookmark icon button at the top-right corner of the article card. For this we’ll be using a Stack
widget.
As the name suggests, it arranges widgets on top of each other. Wrap the Placeholder
widget with a Stack
and update your code as follows:
...
Stack(
children: [
const Placeholder(
fallbackHeight: 200,
),
Positioned(
top: 10,
right: 10,
child: IconButton(
icon: const Icon(Icons.bookmark_border, size: 32),
onPressed: (){},
),
),
],
),
...
Save your work. You can see that the bookmark icon is placed at top-right corner on top the placeholder widget. Okay, lets break down what’s going on here.
The Stack
takes in a List of children
. The first child is the base of the Stack
and any other widget is placed on top of it. The bookmark icon is the next child so it placed on top of the placeholder widget. And this structure continues in that order.
So the arrangement of the children is very important. A good example of a Stack
layout is a stack of playing cards.
Last In, Firt Out or Last In, First Seen. Next, to position the icon where we want it inside the Stack
, we use a Positioned
widget. We set its top and right distance to 10. This aligns the icon to the top-right corner and insets it on both the top and right edges of Stack by a value of 10.
We need to update the Placeholder
with an image. Let’s do that in the next episode.