Coding an Android App With Flutter and Dart

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.

Coding an Android App With Flutter and Dart

Coding an Android App With Flutter and Dart
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:

  1. Flutter uses Dart, a fast, object-oriented language with several useful features such as mixins, generics, isolates, and optional static types.
  2. 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.
  3. 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

Coding an Android App With Flutter and Dart

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.

Coding an Android App With Flutter and Dart

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.

Coding an Android App With Flutter and Dart

Similarly, search for and install the Flutter plugin.

Coding an Android App With Flutter and Dart

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.

Coding an Android App With Flutter and Dart

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.

Coding an Android App With Flutter and Dart

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:

Coding an Android App With Flutter and Dart

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.

Coding an Android App With Flutter and Dart

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:

Coding an Android App With Flutter and Dart

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.

Coding an Android App With Flutter and Dart

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.