A Simple Stopwatch App with Flutter
Flutter is a relatively new player in the world of code once, run everywhere frameworks. Of course, the recent hype being React Native in this genre of frameworks, Flutter has naturally been widely compared with that from pretty much its inception. While there may be pros and cons to both of these, and much enthusiasm to adopt either, to me, with my limited experience with Flutter and a bit less limited one with React Native, I can already see how much easier it is to get started with the Google’s one. I mean, the ease of getting started with a new framework depends more on the tooling and documentation available from the creators than on the ease of using the framework itself. And to that regard, Google has done a tremendously better job than Facebook. I won’t get into further details regarding this as that’s beyond the scope of this post, but as the following tutorial assumes that you already are somewhat familiar (being able to create a new Flutter project and running a Hello World app is enough) with the structure of a Flutter project, I am linking the Getting Started guide here for you to decide for yourself.
About the project
As the title mentions, the project will be a simple app containing a stopwatch. It will have the following:
- A start/stop button
- A reset button
- A text field to show the elapsed time. For the sake of simplicity and keeping the tutorial short, we won’t bother too much about the user interface and some other finer details.
When we are done, the app should look like the following:
Set the project up
I hope by now you have finished going through the Flutter basics from the link I have mentioned above, if not, this is the perfect time to do so. As you probably already know by now, there are quite a few ways to start a new Flutter project. We are going to stick to the basics and create one using the command line. The command for this is:
Let’s name our project flutter_stopwatch
, so the command for this case becomes:
Configure the root of the app
The previous command creates the project and adds some default code to it in main.dart
. We are not going to use this file for much more than a starting point for our app, so let's just go ahead and replace everything in it with the following code:
A few things need to be explained here,
- Our main code for the home view will be in another file named
home.dart
, we still haven't created it yet, so your editor might show an error here. - We are using the green theme here.
- Continuing from 1, our home view in the
home.dart
file will be an widget namedHomeWidget
. This is all there is to this file for now. Next we move on to creating thehome.dart
file and and our home widget.
Add the home widget
Create the home.dart
file and add the following code:
The code here is pretty straight forward, the only thing of note here is,
- The
HomeWidget
class will have states to maintain the various stopwatch related data, so we extendStatefulWidget
, - We mention a new class here, namely
HomeWidgetState
, as the name suggests, this should handle the states forHomeWidget
.
Add the state class for the home widget
Add the following below the previous block of code:
The code here is again simple enough, the key points being,
- We extend
State
and passHomeWidget
as the type, making the resultingHomeWidgetState
class ready to be used asHomeWidget
's state. - We set the title text for the top bar.
- The actual body of the home widget is set as
null
for now. We will add stuff to it in the next section.
Now we are ready to run our app for the first time. Run it and if everything goes well, you should be greeted with the following blank screen. Pretty eh?
Add the buttons
We will start the actual work by adding the Start/Stop button. To do this, let’s add a new variable and a couple of methods to HomeWidgetState
, so the class looks like this:
The main takeaways here,
- We add a variable to hold the current display text for the Start/Stop button.
- Body of the
HomeWidgetState
is provided by the_buildBody()
method now. - The body is a
Column
widget, which will arrange the children vertically one after another in our app. - We use a
RaisedButton
widget as our button. - We use the variable added above to show the button’s title text.
Running the app now gives us the following:
Not much to look at yet, but we have got our button! Now we will add a button to reset the timer similarly as the previous one. Modify the code to look like the following:
Running the app now should show the Reset button below the Start/Stop button.
Adding the stopwatch and the rest
Now that we have a base, the rest of the task is not much complicated. First we add a String
to hold the timer value below _buttonText
,
Then we add the Text
to show this value, so the _buildBody()
method becomes:
To explain the marked lines:
- We use an
Expanded
widget to make theText
widget show up at the center of the empty space below the buttons, instead of right below them. Check the Flutter documentation to know more about this widget. - We use
TextStyle
to give theText
a font size of 72, making it nice and big.
At this point, the UI is very much how we wanted it to be. So it’s time to add the logic to make it all work. We’ll add the rest of the stuff at once and go through them one by one. The final version of the HomeWidgetState
class should look like this:
The last bit to make this all work, we need to add import dart:async;
at the top as the Timer
class we use is part of it. Let's go through the things we have done here one by one:
- We add a
Stopwatch
object to take care of the actual stopwatch. - We add a timeout to refresh the UI, and set it to 1 second interval.
- Calling the
_startTimeout
method surrounding this line starts a newTimer
with the previously specified timeout interval, which upon expiry, calls the_handleTimeout
method. - At each timeout, we update the stopwatch text.
- We check if the stopwatch is running, and stop it if it is.
- Otherwise we start the stopwatch.
- If the stopwatch is running when reset is pressed, we first stop it first leveraging existing code.
- This is the method responsible for setting up the stopwatch text.
So we finally have our very basic stopwatch! Now to run it and make sure everything works.
Conclusion
I hope I was able to demonstrate that the ease of working with Flutter goes beyond setting it up and into the actual workflow of building great cross platform applications with it. You can download the final version from here. Please let me know if you have any feedback in the comments. Thanks for reading!