Flutter Challenge: The Medium App
Flutter Challenges will attempt to recreate a particular app UI or design in Flutter.
Today we’ll attempt to create the home screen of the Medium app. Note that the focus will be on the UI rather than actually fetching articles.
Getting Started
Before developing a design, identify the components required to make the screen in any framework.
The app screen has a drawer, a notification and search option, and a list of articles.
Let’s take a look at the article
At the very top, the article has a text which gives you relevance as to why it’s there. For example, if it’s based on your reading history or if it’s from a category you follow.
Below that is the title of the article itself, which is bold and black as to stand out.
Below the title is the author of the article, date of publishing, and how long the article is estimated to take to read.
On the right hand side is the article image and a bookmark button for saving it for later.
Setting up the app
Create a new Flutter, example: “medium_app_ui”.
Remove the code for the counter app until you only remain with a Scaffold with an AppBar.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Home',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Home"),
),
body: new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
],
),
),
);
}
}
This is the app with a simple app bar.
Before we move on to the list, let’s construct the AppBar according to the Medium design.
As of now, the appBar is blue. We need to change the app bar to black. The actions on the appBar are notifications and search. Doing these changes:
appBar: new AppBar(
title: new Text("Home"),
backgroundColor: Colors.black,
actions: <Widget>[
Icon(Icons.notifications_none, color: Colors.grey,),
Icon(Icons.search, color: Colors.grey),
],
),
After this, we need to adjust a few icons and add a drawer. To add a drawer without any content, simply add
drawer: Drawer(),
to your Scaffold.
Here is the code and resulting AppBar.
So far, so good.
Let’s create a class to store articles named NewsArticle.dart
class NewsArticle {
String categoryTitle;
String title;
String author;
String date;
String readTime;
String imageAssetName;
NewsArticle(this.categoryTitle, this.title, this.author, this.date,this.readTime, this.imageAssetName);
}
For now, they’re just hardcoded articles.
Creating the List
To create a repeating list in Flutter, we use ListView.builder().
In the image, the cards are over a grey background.
Let’s analyse the card components themselves.
There’s a class named NewsHelper which provides the hard-coded articles.
The final item is build like this:
Padding(
padding: const EdgeInsets.fromLTRB(0.0,0.5,0.0,0.5),
child: Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(article.categoryTitle, style: TextStyle(color: Colors.black38,fontWeight: FontWeight.w500, fontSize: 16.0),),
Padding(
padding: const EdgeInsets.fromLTRB(0.0,12.0,0.0,12.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Flexible(child: Text(article.title, style: TextStyle(fontWeight: FontWeight.bold, fontSize: 22.0),), flex: 3,),
Flexible(
flex: 1,
child: Container(
height: 80.0,
width: 80.0,
child: Image.asset("assets/" + article.imageAssetName, fit: BoxFit.cover,)
),
),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(article.author, style: TextStyle(fontSize: 18.0),),
Text(article.date + " . " + article.readTime, style: TextStyle(color: Colors.black45, fontWeight: FontWeight.w500),)
],
),
Icon(Icons.bookmark_border),
],
)
],
),
),
),
);
Designing the Drawer
This is how the drawer looks on the Medium app:
The Drawer is simply a Column with a list of elements and an Image at the top. The top white portion can be represented by one container and the bottom half by another.
Here is the drawer in code:
Drawer(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
child: Padding(
padding: const EdgeInsets.fromLTRB(32.0,64.0,32.0,16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Icon(Icons.account_circle, size: 90.0,),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("John Doe", style: TextStyle(fontSize: 20.0),),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("See profile", style: TextStyle(color: Colors.black45),),
)
],
),
),
),
Expanded(
child: Container(
color: Colors.black12,
child: Padding(
padding: const EdgeInsets.fromLTRB(40.0,16.0,40.0,40.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Home", style: TextStyle(fontSize: 18.0),),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Audio", style: TextStyle(fontSize: 18.0),),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Bookmarks", style: TextStyle(fontSize: 18.0),),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Interests", style: TextStyle(fontSize: 18.0),),
),
Divider(),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Become a member", style: TextStyle(fontSize: 18.0, color: Colors.teal),),
),
Divider(),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("New Story", style: TextStyle(fontSize: 18.0),),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Stats", style: TextStyle(fontSize: 18.0),),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text("Drafts", style: TextStyle(fontSize: 18.0),),
),
],
),
),
),
),
],
),
),
Here is the final code of the page:
That’s it for today. Feel free to suggest any other apps you may want to see recreated in Flutter.
Project GitHub link : https://github.com/deven98/MediumAppFlutter
More where this came from
This story is published in Noteworthy, where thousands come every day to learn about the people & ideas shaping the products we love.
Follow our publication to see more product & design stories featured by the Journal team.