If you are looking for alternative approaches to Android application development, you should consider giving Google's Flutter, a framework based on the Dart programming language, a try.
Apps built with Flutter are largely indistinguishable from those built using the Android SDK, both in terms of looks and performance. What's more, with minor tweaks, they can be run on iOS devices as well.
In this tutorial, I'll introduce you to the basics of Flutter by showing you how to build a simple tip calculator app for Android.
Prerequisites
To be able to follow this tutorial, you'll need:
- the latest version of IntelliJ IDEA
-
Android Studio 2.2 or higher
- a device or emulator running Android 4.4 or higher
- a computer running Mac or Linux
1. Why Use Flutter?
Running at 60 fps, user interfaces created with Flutter perform far better than those created with other cross-platform development frameworks such as React Native and Ionic. If that doesn't excite you, here are a few more reasons why you might want to use Flutter:
- Flutter uses Dart, a fast, object-oriented language with several useful features such as mixins, generics, isolates, and optional static types.
- Flutter has its own UI components, along with an engine to render them on both the Android and iOS platforms. Most of those UI components, right out of the box, conform to the guidelines of Material Design.
- Flutter apps can be developed using IntelliJ IDEA, an IDE that is very similar to Android Studio.
2. Installing Flutter
You can get the latest version of Flutter by cloning its GitHub repository.
git clone https://github.com/flutter/flutter.git
Flutter has several dependencies, such as the Dart SDK and Material Design fonts. Fortunately, the first time you run Flutter's diagnostic tool, all of them are installed automatically.
cd flutter/bin ./flutter doctor
To be able to build Android apps, you must also point Flutter to the directory where you installed Android Studio.
./flutter config --android-studio-dir ~/android-studio
3. Configuring IntelliJ IDEA
Although you can directly use Flutter's CLI to create and run new apps, you're likely to have a far better development experience if you use an IDE. The recommended IDE for Flutter is IntelliJ IDEA.
Before you start developing Flutter apps with it, however, you must install plugins for both Dart and Flutter. To do so, start by selecting Configure > Plugins in the IntelliJ welcome screen.
In the dialog that pops up, press the Browse repositories... button and search for the Dart plugin. Once you find it, press the Install button to install it.
Similarly, search for and install the Flutter plugin.
Once both the plugins are installed, restart IntelliJ IDEA.
You must now point the Flutter plugin to the directory in which you installed Flutter. To do so, select Configure > Settings in the welcome screen and, in the dialog that pops up, navigate to Languages & Frameworks > Flutter. In the Flutter SDK path field, type in the absolute path of the directory.
Press OK to complete the configuration.
4. Creating a New Project
To create a new Flutter project, press the Create New Project button in the welcome screen. In the New Project dialog, choose Flutter and press Next.
You can now give a meaningful name to your project and press Finish.
Once the project has been generated, I suggest you press the Run button to make sure that the Dart SDK, the plugins, and the Flutter framework are all configured correctly. If they are, after several seconds, you should see the following screen on your device or emulator:
Note that, from this point on, you don't have to press the Run button again even after making code changes. Flutter supports hot reload, a feature that allows you to instantly push updates to the app without restarting it.
5. Creating Widgets
In this tutorial, we'll be creating a tip calculator app with the following widgets:
- a
TextField
to accept a bill amount
- a
TextField
to accept a tip percentage
- a
RaisedButton
the user can press to calculate the tip
Each Flutter widget can either be a StatelessWidget
or a StatefulWidget
. As its name suggests, a StatefulWidget
has a State
object associated with it, which allows it not only to store data, but also to react to changes in the data.
A StatelessWidget
, on the other hand, is a simpler object, not designed to persistently store any data. To keep this tutorial short, we'll be creating our tip calculator as a StatelessWidget
. Therefore, open main.dart, remove all its contents, and add the following code to it:
import 'package:flutter/material.dart'; class TipCalculator extends StatelessWidget { }
In the above code, the import
line is important because material.dart is the library that contains all the Material Design widgets we'll be using in this app.
To store the bill amount and the tip percentage, add two member variables to the class.
double billAmount = 0.0; double tipPercentage = 0.0;
To start creating the user interface of the app, override the build()
method.
@override Widget build(BuildContext context) { // More code goes here }
Let us now create the two TextField
widgets. While doing so, we can specify details such as the labels we want to associate with the widgets and the types of the virtual keyboards that must be displayed when they are in focus.
Because we can't directly retrieve the contents of a TextField
widget, we must also associate an onChanged
event handler with it. Inside the handler, which receives an InputValue
object, we can update the contents of our class's member variables.
Accordingly, add the following code inside the build()
method:
// Create first input field TextField billAmountField = new TextField( labelText: "Bill amount(\$)", keyboardType: TextInputType.number, onChanged: (InputValue value) { try { billAmount = double.parse(value.text); } catch (exception) { billAmount = 0.0; } } ); // Create another input field TextField tipPercentageField = new TextField( labelText: "Tip %", keyboardType: TextInputType.number, hintText: "15", onChanged: (InputValue value) { try { tipPercentage = double.parse(value.text); } catch (exception) { tipPercentage = 0.0; } } );
Even if you have never worked with Dart before, the above code should be fairly intuitive, so long as you are familiar with Java. For instance, you can see that we are using the parse()
method to convert each TextField
widget's text content to a double
object. Because the parse()
method can throw a FormatException
, it is also surrounded by a try...catch
block.
Creating a RaisedButton
widget is much like creating a TextField
widget. However, to assign a label to it, you must create a new Text
widget and add it as its child
.
// Create button RaisedButton calculateButton = new RaisedButton( child: new Text("Calculate"), onPressed: () { // More code goes here } );
Inside the onPressed
event handler of the button, we'll calculate the tip and the total amount to be paid, and display both inside a modal dialog. To create the dialog, we can use the AlertDialog
class. Once created, the dialog can be displayed by passing it as an argument to the showDialog()
method.
Accordingly, add the following code inside the onPressed
event handler:
// Calculate tip and total double calculatedTip = billAmount * tipPercentage / 100.0; double total = billAmount + calculatedTip; // Generate dialog AlertDialog dialog = new AlertDialog( content: new Text("Tip: \$$calculatedTip \n" "Total: \$$total") ); // Show dialog showDialog(context: context, child: dialog);
In the above code, note that we've used Dart's string interpolation feature to embed variables inside the content
of the dialog. Also, you can see that string literals in Dart can be concatenated just by placing them beside one another—though you can use the +
operator too, if you like.
6. Creating a Widget Tree
A Flutter app is usually nothing but a tree of widgets. In other words, you create a Flutter app by simply creating multiple widgets and establishing parent-child relationships between them.
Currently, there are no relationships between the widgets we created in the previous step. As you might have guessed, they are all going to be siblings, so let's now create a parent widget for them.
A widget that can have multiple children is usually referred to as a layout widget. Flutter offers several layout widgets to choose from. For our app, the Column
widget is most appropriate because it positions all its children one below the other.
Additionally, in order to conform to the Material Design spec, we must add a padding of 16 dp to the Column
widget. We can do so by making it a child
of a Container
widget.
Container container = new Container( padding: const EdgeInsets.all(16.0), child: new Column( children: [ billAmountField, tipPercentageField, calculateButton ] ) );
A Material Design user interface is not complete without an app bar. Therefore, create one now using the AppBar
widget.
AppBar appBar = new AppBar(title: new Text("Tip Calculator"));
Layouts containing app bars and containers are so common that Flutter offers a Scaffold
widget to help you quickly establish a relationship between them.
Scaffold scaffold = new Scaffold(appBar: appBar, body: container);
With the Scaffold
widget at its root, our widget tree is now ready. You can go ahead and use the Scaffold
widget as the return value of the build()
method.
return scaffold;
If you are finding it hard to visualize the tree, the following diagram should help:
7. Creating an Entry Point
Our Dart file needs a main()
function as its entry point. Inside it, we must call the runApp()
function to actually inflate and render the widget tree we created in the previous step.
Additionally, our TipCalculator
widget must be placed inside a MaterialApp
widget so that a Material Design theme and color scheme can be applied to it. Therefore, add the following code to main.dart:
void main() { runApp(new MaterialApp( title: 'Tip Calculator', home: new TipCalculator() )); }
You can now press the Hot Reload App button to start using the app on your device.
Conclusion
In this tutorial, you learned how to use Flutter and Dart, along with IntelliJ IDEA, to create a simple app for Android.
In my opinion, Flutter has almost everything a developer might look for in a cross-platform mobile app development framework. Before you decide to start building your next big app with it, however, be aware that it is still a very new and rapidly evolving framework.
To learn more about Flutter, you can refer to its official documentation.
Comments