Creating a Home Screen | How to Develop an App with Flutter – Part 3
Learn how to build your first app with Flutter. This time we will focus on creating home screen.
Want to build an app with Flutter? Follow our series “Flutter app development tutorial for beginners”. We’ve published the following posts so far:
- Introduction to your first Flutter app development
- Flutter Project Setup
- Creating a Home Screen – you are reading this
- Styling the Home Screen
- Networking and connecting to API
- Refining Widgets’ Layer with Provider
- Internationalizing and Localizing your Flutter App
What’s more, we’ve also prepared a Roadmap that can be useful in your Flutter development journey:
- Roadmap for Flutter developers in 2020 – feel invited to contribute!
Whether you want to work at Flutter development company or be a freelancer, this knowledge will help you to become a Flutter developer.
Creating a home screen in the Smoge app with Flutter – introduction
In the last post about project setup with Flutter, Karol showed us how to set the Flutter environment up, so without any additional work, we can dive into the best part – coding 🙂
In this article, we will learn, step by step, how to create a home screen of the Smoge app with Flutter. In particular, we will focus on:
- organizing your project with smaller classes and directories
- building UI using basic Flutter widgets
- creating a custom widget and animations
- using assets in Flutter
- writing the code that will be easily maintainable.
This is a preview of what we want to achieve:
Download the initial code, that will be used as a basis for this part here.
The final implementation of the first screen is available here.
Skip to a section:
- Splitting the code up
- Building a city title widget
- Creating an animated widget
- Placing an animated widget on the home screen
- Creating a custom widget
- Building a single activity widget
- Building an activities widget
- Placing the activities widget on the home page
- Wrapping the last screen element up
- Summary
There are many successful apps made with Flutter on the market. Maybe your will be the next one! So, let’s get to work.
Splitting the code up
In the lib folder, we can find the main.dart
file. This file is created automatically together with the entire project. Inside this file, we find three main parts:
main()
function which is the entry point for the app. This function callsrunApp()
to start the framework.MyApp
class, which is the root of the whole app. Here we can define a home screen and a theme for the whole app.MyApp
extendsStatelessWidget
which makes the whole app itself also a widget.MyHomePage
class, which is a home screen of the app. It extendsStatefulWidget
. That means the home screen has itsState
object (_MyHomePageState
that starts its definition at line 46). This widget could look differently depending on its internal objects(in this case it’scounter
parameter).
As you can see, all of these parts are in just one file. Let’s start with a small refactoring and move all these parts to separate files and remove default comments.
Create two directories in the lib folder:
- app – to store classes related to app configuration: colors, icons themes, etc.
- ui – to store screen classes
Create smoge_app.dart
in the app directory. Move MyApp class to the newly created file and rename it to SmogeApp.
Keep in mind that the file naming convention in Dart is using only lowercase letters and underscores for word separation. More about Dart language style you can read at Dart’s guide website.
Move MyHomePage
class to lib/ui/home
directory and rename the class to HomePage
. Also, remove code related to the counter as we will not use it.
In main.dart
leave only the main
method that runs SmogeApp
. After that, the code is more separated, easier to read, and maintain.
One more thing we need to change to make the project compile is to rename MyApp
to SmogeApp
in widget_test.dart.
Now we can run the app and see only a navigation bar and a white background.
Now, let’s go to the next important element useful when you want to create your first app with Flutter and learn how to build a Flutter app – Building UI.
Building city title widget
As a top widget of our home screen, we will use SafeArea
.
SafeArea widget adds padding depending on the operating system to avoid overlapping with a status bar or a notch on some phones.
The whole content is aligned vertically one after another so as a child of SafeArea
we will use Column widget.
At the top of the screen, we have a label with a city name. To build it we will use Text widget.
And that is enough for now. Let’s put that in code and change _HomePageState
like this:
Building of the title is located in a separate method to make code cleaner and easier to read.
Underscore (_) as a function’s prefix is used in Dart to mark this function private.
And now run the app.
The text label is below the status bar and notch due to the SafeArea
widget.
But the text label is not centered horizontally on the screen. Why?
The problem is that the Column
widget adjusts its width to cover all the content, so in our case Column
width is the same as a text label.
To stretch column full screen add property crossAxisAlignment
and set it to CrossAxisAlignment.stretch
.
Now It looks better. Text size and font of the text label is not the same as on designs but we will fix that later 🙂
In the next paragraph, I describe another crucial element useful if you want to learn how to build an app with Flutter. Creating animations.
Creating animated widget
The next step is to create a text with a percentage at the center. This text needs to be animated from the value of zero to the given number.
Animations, Yay!
We are going to create this widget in a separate class and we will pass two values to it: fromValue
and toValue
. All animation logic will be inside this widget so our home page will stay clean and readable.
First, in the home directory create a new one called widgets. Here we will create all custom widgets needed on the home page. Create new Dart file animated_percentage_widget.dart
and paste below code:
AnimatedPercentageWidget
extends StatefulWidget
because its state will be changed during the animation.
In the constructor, we can pass three parameters: fromValue
, toValue
, and duration
. We set a default value for the duration
parameter so it can be omitted during widget creation. Before calling the super
method we check if all required values aren’t nulls to avoid null pointer exceptions and application crash. Also, we check if fromValue
is less than toValue
.
The default value of the duration
parameter is created with the const
keyword.
const
is an optimization. It helps Flutter to easily compare representations of widgets and decide if it needs to be rebuilt.
To use the const
keyword all widget’s parameters have to be final.
The more detailed explanation you can find in this post.
createState()
method needs to be overridden for a stateful widget in order to create data that will drive the widget.
_AnimatedPercentageWidgetState
is a private class that extends State
, a generic abstract class. It is a Flutter template for creating custom widgets.
To run animation in Flutter we need instances of two classes: Animation and AnimationController
In our animation, we will use a ticker controller and a setState
method.
A Ticker
is an object that calls a function every frame.
Widget state includes SingleTickerProviderStateMixin
. This mixin takes care of the hassle of managing the ticker. With that mixin, our state becomes secretly a ticker provider. What this means, is that the Flutter framework can ask it for a ticker.
Most importantly, AnimationController
can ask it for a ticker.
AnimationController
needs a ticker for its two functions. If you use SingleTickerProviderStateMixin
or its cousin TickerProviderStateMixin
you can give ‘this’ to the AnimationController
.
AnimationController
is what you normally use to play, pause, reverse, and stop animations.
Instead of pure tick events, it tells us at which point of the animation we are at any time.
In our case we want to animate from one value to another, so we will use Tween animation.
In the Tween
constructor we put fromValue
as begin
and toValue
as end
parameters.
Right after the constructor, we call animate
function passing AnimationController
as its parameter. This function returns Animation
which is driven by a passed controller.
On the animation object, we call addListener
function to be notified every time the value of the animation changes.
The standard way of setting a listener would create animation and then set the listener on the animation object like this:
Thanks to Dart’s cascade notation we can call the subsequent ‘addListener method on the
Animation object. ‘addListener
is a void method so it does not return any value but as a cascade notation ignores any subsequent return value we still get Animation
object and can assign it to _animation
parameter:
Inside the listener we call the setState
method. setState
notifies the framework that the internal state of the object has changed. In our case, we change the _number
parameter value to one provided by animation.
The last step is to call the forward
method on the controller to start running animation.
Don’t forget to dispose of AnimationController
. This can be done in the dispose
method of the widget’s state.
As the animation is ready, what’s left is to build a Text
widget with _number
value:
Placing an animated widget on the home screen
Now is the time to add just created widget to the home screen. Let’s do the same for building this widget as it was for the title which is in a separate method.
Both with percentage value let’s add a label that is underneath.
Both widgets are one after another vertically so wrap them in Column
:
Running the app we get such results:
The animation is working!
The whole content should be placed in the center. To achieve that we need to wrap the created column in Expanded widget, so it will take free space of parent Column
and also to center content vertically inside it we will set mainAxisAlignment
to MainAxisAlignment.center
.
And now the content is in the center!
Creating custom widget
What we are missing on the home screen is a bottom widget with the activities.
This one will also be created as a separate widget to keep code well organized.
We will need some icons to build this widget so let’s start with that.
In the assets
folder at the root of the project, you can find all the needed assets.
Flutter uses the pubspec.yaml
file to identify assets used in the project.
Open this file and in the flutter
section and assets
subsection, we have to define all assets that the project uses.
To add images
folder to be used by the app make such entry in the pubspec
file:
Keep in mind that in case of adding files from subdirectories, we need to create an entry for each directory.
Having assets included in the project, let’s dive into widget building.
Inside the activities widget, there are three separate activities places horizontally.
Every activity looks similar, so it is a good idea to make a separate widget from it.
Building a single activity widget
So start with creating ActivityWidget
:
There will be three types of activities: walking, running, and biking.
And we want to display a mark if air quality is good or bad for a given activity.
Create enums with all those types:
To ActivityWidget
we will pass activity type and quality. Depending on those two values, the widget can be configured appropriately.
Let’s go step by step through this file.
- At the top, there is a private abstract class in which constant values are defined.
- Next, there are two enums described before. Enums were moved to this file in a matter of readability.
ActivityWidget
extendsStatelessWidget
as it won’t change during the widget lifecycle.- The constructor receives two parameters:
ActivityType
andActivityQuality
. - At the bottom of the file, there are three helper methods. One
_titleForActivityType
returns activity name based on passedactivityType
and the second one_imageForActivityType
do the same but instead of name it returns an icon for activity.
The last one_buildWarningBadge
returns a proper widget depending on passedActivityQuality
: an empty container for good quality and anImage
widget with a warning icon for bad quality. - The
build
method creates the whole widget using helper methods. Because the building is complex, private methods were created to make it easier to read.
As a parent widget, we used Expanded as it has to expand in its parent.
Next in the hierarchy, we put Stack to show badge warning icons above the rest of the content.
InsideStack
, we placed a badge icon at the top, right corner. To do that badge icon have to be wrapped by a Positioned widget:The second child of aStack
is an activity container that has a white background with rounded corners and a column of an activity icon and name.
TheContainer
has padding from right and top equal to half the size of the warning badge. To achieve that we wrap the container with Padding widget:To build an activity container with rounded corners and shadow we used Container widget with box decoration:Inside the container, one thing that misses is the activity icon and name. These two are children of Column centered in a container.
Building an activities widget
As the ActivityWidget
is finished it is time to create a widget showing all activities with their quality:
ActivitiesWidget
accepts Map where the key is activity type and value is activity quality. Iterates through that map widget build next ActivityWidgets
:
To place the elements horizontally we use Row. To make sure the spacing between elements as well as before and after the first and the last element is equal we set mainAxisAlignment
to MainAxisAligement.spaceEvenly
.
The activities widget is ready!
Placing an activities widget on the home page
Let’s add it home page to the bottom of the screen with bottom padding:
And run the app:
And it looks pretty good, doesn’t it? 🙂
Wrapping last screen element up
The last thing, that is missing on the main screen is the details label with an arrow underneath.
To build that we will use a well known already Column
Based on the design text has 50% opacity. To achieve that in Flutter we wrap Text
in the Opacity widget.
Running the app we can see that the percentage widget takes the whole free space and the details are placed just above activities with height adjusted to its content.
What we want to achieve is to have the percentage at the center between the top label and bottom activities and details at the center between the percentage and activities.
To do that we will create Column
with three children:
- Expandable container to fill top free space
- Air pollution information with height fitting its content
- Details column wrapped with
Expanded
to fill space below the air pollution information
To place the percentage at the center, the Expanded
widget above and below it has to have the same flex
value.
flex
determines the amount of space the child can occupy in the main axis by dividing the free space according to the flex factors of the flexible children.
The default value of flex
is 1. It means that both Expanded
widgets above and below percentage will occupy the same amount of space and with that, the percentage widget will be at the center.
It should look like this:
And the code looks like this:
The air pollution column is not wrapped in Expanded
anymore so it shrinks to content size.
The details column is wrapped in Expanded
to increase its size to available free space.
And the home screen looks as we desired.
And that’s it for now!
Congratulations, you have built your first UI in Flutter 🙂
In the next post, we will style the app by adding colors and text styles.
We will also learn how to add the smoke effect in the background.
Creating a home screen in Smoge app with Flutter – summary
We’ve learned how to create a beautiful home screen in your first Flutter app. We discussed elements like organizing your project with smaller classes and directories, building basic UI with Flutter widgets, and using assets.
I hope our Flutter tutorial for beginners will help you in getting started with your Flutter mobile app development. Read the next article about styling the app with Flutter, by adding colors and text styles.
In the meantime, you can check out in10 – RSVP & ETA Tracking App which we made with Flutter.
About the author
Want to create a mobile app with Flutter?
Entrust your Flutter app development in the best hands of an experienced team