In this blog post, we will explore the basics of cross platform mobile application development using Flutter, compare it with existing cross-platform solutions and create a simple to-do application to demonstrate how quickly we can build apps with Flutter.
Flutter is a free and open source UI toolkit for building natively compiled applications for mobile platforms like Android and iOS, and for the web and desktop as well. Some of the prominent features are native performance, single codebase for multiple platforms, quick development, and a wide range of beautifully designed widgets.
Other interesting Dart features used in Flutter apps is the just-in-time (JIT) compiler, used during development and debugging, which powers the hot reload functionality. And the ahead-of-time (AOT) compiler which is used when building applications for the target platforms such as Android or iOS, resulting in native performance.
Everything composed on the screen with Flutter is a widget including stuff like padding, alignment or opacity. The Flutter engine draws and controls each pixel on the screen using its own graphics engine called Skia.
Flutter vs React-Native
React Native, on the other hand, has the advantage of being older and hence has a large community of businesses and developers who have experience in building react-native apps. It also has more third party libraries and packages as compared to Flutter. That said, Flutter is catching up and rapidly gaining momentum as evident from Stackoverflow's 2019 developer survey, where it scored 75.4% under "Most Loved Framework, Libraries and Tools".
All in all, Flutter is a great tool to have in our arsenal as mobile developers in 2020.
Getting started with a sample application
Flutter's official docs are really well written and include getting started guides for different OS platforms, API documentation, widget catalogue along with several cookbooks and codelabs that one can follow along to learn more about Flutter.
To get started with development, we will follow the official guide which is available here. Flutter requires Flutter SDK as well as native build tools to be installed on the machine to begin development. To write apps, one may use Android Studios or VS Code, or any text editor can be used with Flutter's command line tools. But a good rule of thumb is to install Android Studio because it offers better support for management of Android SDK, build tools and virtual devices. It also includes several built-in tools such as the icons and assets editor.
Once done with the setup, we will start by creating a project. Open VS Code and create a new Flutter project:
We should see the main file main.Dart with some sample code (the counter application). We will start editing this file to create our to-do app.
Some of the features we will add to our to-do app:
- Display a list of to-do items
- Mark to-do items as completed
- Add new item to the list
Let's start by creating a widget to hold our list of to-do items. This is going to be a StatefulWidget, which is a type of widget with some state. Flutter tracks changes to the state and redraws the widget when a new change in the state is detected.
After creating theToDoList widget, our main.Dart file looks like this:
The ToDoApp class here extends Stateless widget i.e. a widget without any state whereas ToDoList extends StatefulWidget. All Flutter apps are a combination of these two types of widgets. StatelessWidgets must implement the build() method whereas Stateful widgets must implement the createState() method.
Some built-in widgets used here are the MaterialApp widget, the Scaffold widget and AppBar and Text widgets. These all are imported from Flutter's implementation of material design, available in the material.dart package. Similarly, to use native looking iOS widgets in applications, we can import widgets from the flutter/cupertino.dart package.
Next, let's create a model class that represents an individual to-do item. We will keep this simple i.e. only store label and completed status of the to-do item.
The constructor we wrote in the code above is implemented using one of Dart's syntactic sugar to assign a constructor argument to the instance variable. For more such interesting tidbits, take the Dart language tour.
Now let's modify the ToDoListState class to store a list of to-do items in its state and also display it in a list. We will use ListView.builder to create a dynamic list of to-do items. We will also use Checkbox and Text widget to display to-do items.
A few things to note here are: private functions start with an underscore, functions with a single line of body can be written using fat arrows (=>) and most importantly, to change the state of any variable contained in a Stateful widget, one must call the setState method.
The ListView.builder constructor allows us to work with very large lists, since list items are created only when they are scrolled.
Another takeaway here is the fact that Dart is such an intuitive language that it is quite easy to understand and you can start writing Dart code immediately.
Everything on a screen, like padding, alignment or opacity, is a widget. Notice in the code above, we have used Padding as a widget that wraps the list or a text widget depending on the number of to-do items. If there's nothing in the list, a text widget is displayed with some default message.
Also note how we haven't used the new keyword when creating instances of a class, say Text. That's because using the new keyword is optional in Dart and discouraged, according to the effective Dart guidelines.
Running the application
At this point, let's run the code and see how the app looks on a device. Press F5, then select a virtual device and wait for the app to get installed. If you haven't created a virtual device yet, refer to the getting started guide.
Once the virtual device launches, we should see the following screen in a while. During development, the first launch always takes a while because the entire app gets built and installed on the virtual device, but subsequent changes to code are instantly reflected on the device, thanks to Flutter's amazing hot reload feature. This reduces development time and also allows developers and designers to experiment more frequently with the interface changes.
As we can see, there are no to-dos here yet. Now let's add a floating action button that opens a dialog which we will use to add new to-do items.
Adding the FAB is as easy as passing floatingActionButton parameter to the scaffold widget.
And declare a function inside ToDoListState that displays a popup (AlertDialog) with a text input box.
At this point, saving changes to the file should result in the application getting updated on the virtual device (hot reload), so we can just click on the new floating action button that appeared on the bottom right of the screen and start testing how the dialog looks.
We used a few more built-in widgets here:
- AlertDialog: a dialog prompt that opens up when clicking on the FAB
- TextField: text input field for accepting user input
- InputDecoration: a widget that adds style to the input field
- FlatButton: a variation of button with no border or shadow
- FloatingActionButton: a floating icon button, used to trigger primary action on the screen
Here's a quick preview of how the application should look and function at this point:
And just like that, in less than 100 lines of code, we've built the user interface of a simple, cross platform to-do application.
The source code for this application is available here.
A few links to further explore Flutter:
To conclude, Flutter is an extremely powerful toolkit to build cross platform applications that have native performance and are beautiful to look at. Dart, the language behind Flutter, is designed considering the nuances of user interface development and Flutter offers a wide range of built-in widgets. This makes development fun and development cycles shorter; something that we experienced while building the to-do app. With Flutter, time to market is also greatly reduced which enables teams to experiment more often, collect more feedback and ship applications faster. And finally, Flutter has a very enthusiastic and thriving community of designers and developers who are always experimenting and adding to the Flutter ecosystem.