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:
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
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 calls
runApp()to start the framework.
MyAppclass, which is the root of the whole app. Here we can define a home screen and a theme for the whole app.
StatelessWidgetwhich makes the whole app itself also a widget.
MyHomePageclass, which is a home screen of the app. It extends
StatefulWidget. That means the home screen has its
_MyHomePageStatethat starts its definition at line 46). This widget could look differently depending on its internal objects(in this case it’s
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
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.
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.
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
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 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
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
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.
We are going to create this widget in a separate class and we will pass two values to it:
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:
StatefulWidget because its state will be changed during the animation.
In the constructor, we can pass three parameters:
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
The default value of the
duration parameter is created with the
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.
In our animation, we will use a ticker controller and 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.
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 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.
Tween constructor we put
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
Inside the listener we call the
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
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
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
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.
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.
images folder to be used by the app make such entry in the
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
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:
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.
StatelessWidgetas it won’t change during the widget lifecycle.
- The constructor receives two parameters:
- At the bottom of the file, there are three helper methods. One
_titleForActivityTypereturns activity name based on passed
activityTypeand the second one
_imageForActivityTypedo the same but instead of name it returns an icon for activity.
The last one
_buildWarningBadgereturns a proper widget depending on passed
ActivityQuality: an empty container for good quality and an
Imagewidget with a warning icon for bad quality.
buildmethod 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.
Stack, 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 a
Stackis an activity container that has a white background with rounded corners and a column of an activity icon and name.
Containerhas 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
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
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
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
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
Expandedto 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 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.