Learn the basics of Flutter and Dart by building a Tip Calculator app in 10 minutes.

Build a Tip Calculator App in Flutter

Ravgeet Dhillon

Ravgeet Dhillon

Written on Sep 27, 2021 in Development

⏱ 14 min read

Blog banner for Build a Tip Calculator App in Flutter

In this tutorial, you’ll create a Tip Calculator app and learn some of the basics of developing a Flutter app. The app will let the user input - Bill Amount and Tip Percentage. Based on these values, it will calculate Tip Amount and Total Amount.

Contents

Getting Started

Flutter lets you create your project on many operating systems. For example, macOS, Linux, Windows, or even Chrome OS.

Before getting started with this project, you’ll need the following things:

You can download the code used in this tutorial from this GitHub repository.

Creating a New Project

The first step is to create a new Flutter project. Open your terminal, navigate to a path of your choice and run the following command:

flutter create tip_calculator

Once your project is set up, navigate into the project directory and open it in your IDE. For VS Code, you can run the following commands:

cd tip_calculator
code .

Locate lib/main.dart file and you’ll find a lot of boilerplate code written for you. You are here to learn to write code on your own, so replace the file contents with the following code:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Tip Calculator',
      theme: ThemeData(primarySwatch: Colors.green),
      home: const FormView(),
    );
  }
}

As you can see in the above code, you need a FormView screen as the home page of your app. So in the lib/main.dart, add the following code:

class FormView extends StatefulWidget {
  const FormView({Key? key}) : super(key: key);
  
  @override
  _FormViewState createState() => _FormViewState();
}

class _FormViewState extends State<FormView> {
  @override
  void initState() {
    super.initState();
  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Tip Calculator'),
      ),
    );
  }
  
  @override
  void dispose() {
    super.dispose();
  }
}

At this point, you have a MyApp class which is a Stateless widget, and a FormView class which is a Stateful widget.

You use a stateful widget when you want to keep track of the state of your app. The UI of a stateful widget is always the function of the state of the widget. For example, a cart page in an eCommerce app. In all other cases, a stateless widget is often handier. It always builds the same UI regardless of the state of the app. For example, the logo for your app on an appbar.

The beauty of Flutter is you can compose Stateful widgets in Stateless widgets. As you develop more and more Flutter apps, you’ll learn to use Stateless widgets more often.

Launching an Emulator Device

At this point, you have enough code to launch your app without any build errors. The next thing you need to do is to connect to a physical device or an emulator. In this tutorial, you’ll work on an emulator.

In VS Code, open the Command Palette by pressing Control-Shift-P, type Flutter: Launch Emulator, and press Enter. Select a Mobile Device emulator and wait for it to initialize.

Menu for selecting Flutter emulator in VS Code

Once your emulator is up and running, press F5 to build and run your Flutter app in debug mode. You’ll see the following screen pop up on your emulator:

Flutter App with Appbar

This screen contains an app bar with your app title.

Building UI

Now your Flutter app is up and running, it is time to build the UI of the app. This app will have a Form with two Text fields and a Column for showing Tip Amount and Total Amount.

Adding a Form for User Input

Update the build function of the _FormViewState class by adding body for your FormView as in the following code:

body: Container(
  padding: const EdgeInsets.all(16.0),
  child: Form(
    child: Column(
      children: [
        TextFormField(
          decoration: const InputDecoration(labelText: 'Bill Amount'),
          keyboardType: const TextInputType.numberWithOptions(
            decimal: true,
          ),
        ),
        const SizedBox(height: 16),
        TextFormField(
          decoration: const InputDecoration(labelText: 'Tip Percentage'),
          keyboardType: const TextInputType.numberWithOptions(
            decimal: true,
          ),
        ),
        const SizedBox(height: 32),
        // todo
      ],
    ),
  ),
),

Save your progress by pressing Control-S and you’ll experience the Hot Reload feature of Flutter. Whenever you update your code, Flutter only rebuilds the part of the widget tree which is dependent upon the changed code rather than rebuilding the entire app. This feature in Flutter is called Hot Reload which lets you develop applications rapidly.

Build and run:

Flutter App with a Form

At this point, you have a Form with two TextFormField widgets for Bill Amount and Tip Percentage.

One of the specifications of the app is to have default values of 0 and 15 for the Bill Amount and Total Amount fields respectively.

So, in the _FormViewState class, add the following two class variables:

double _billAmount = 0;
double _tipPercentage = 15;

Update the TextFormField widget for Bill Amount as in the following snippet:

initialValue: _billAmount.toString(),

Then, update the TextFormField widget for Tip Percentage as in the following snippet:

initialValue: _tipPercentage.toString(),

This will assign a default value to both fields. Since initialValue needs to be a string, so you need to parse the double to a string.

At this point, if you try to do a Hot Reload, it won’t update your app for the changes you have made. This is because the global and static fields relate to the state and Hot Reload excludes any changes made to the app state. In this case, you need to Hot Restart your app.

In VS Code, build and run by pressing Control-Shift-F5 for Hot restart:

At this point, you have successfully rendered your form with two text fields for taking the user input.

Flutter App with Form fields having default values

Adding a Container for Calculations

Your form UI is complete at this stage. Next, you need to add some Text widgets to show the calculations for Tip Amount and Total Amount.

Add the following widget to the build function of the _FormViewState:

Column(
  children: [
    Row(
      children: [
        const Text('Tip Amount: '),
        Text(
          _totalTip.toString(),
          style: const TextStyle(fontWeight: FontWeight.bold),
        ),
      ],
    ),
    const SizedBox(height: 16),
    Row(
      children: [
        const Text('Total Amount: '),
        Text(
          _totalAmount.toString(),
          style: const TextStyle(fontWeight: FontWeight.bold),
        ),
      ],
    ),
  ],
),

If you try to build and run your project, you’ll get some build errors. This is because, in the Text widgets, you are referencing the _tipAmount and _totalAmount variables which you haven’t declared yet.

So, in the _FormViewState class, add the following two class variables:

double _totalTip = 0;
double _totalAmount = 0;

These variables store the calculations related to Tip Amount and Total Amount.

Build and run your project:

Flutter App with Form and Text Labels

At this point, you have successfully rendered a column containing two text labels to show calculations.

Calculating Tip and Total Amount

The app’s UI is complete at this stage. Next, you need to write business logic for calculating Tip Amount and Total Amount.

Updating State

In the _FormViewState class, add the _updateAmounts function as in the following code snippet:

void _updateAmounts() {
  setState(() {
    _totalTip = _billAmount * _tipPercentage / 100;
    _totalAmount = _billAmount + _totalTip;
  });
}

You might ask what is setState? Well, setState is a function provided by a Stateful widget using which you can update the state of your app. Whenever you call setState, Flutter executes the build function associated with the Stateful widget. This updates the UI of your app.

In the setState function, you have used some basic maths for calculating the total tip and total amount.

In this app, you don’t have to worry about government tax. It is better to keep governments out when you are learning something.

Updating UI on User Input

One requirement of this app is to calculate Tip Amount and Total Amount as soon as the user starts typing in the form fields. For this effect, you can use the onChanged callback provided by the TextFormField widget. It runs whenever the user types or deletes anything in a form field. It provides the current value of a form field as a function parameter.

Add the following parameter to the TextFormField widget for Bill Amount:

onChanged: (val) {
  _billAmount = double.tryParse(val) ?? 0;
  _updateAmounts();
},

Then, add the following parameter to the TextFormField widget for Tip Percentage:

onChanged: (val) {
  _tipPercentage = double.tryParse(val) ?? 0;
  _updateAmounts();
},

Here what’s going on in the code above:

  • You cannot assign the val variable to the _billAmount variable as the former is a string and the latter is a double. Hence, you use the double.tryParse function to parse a string to a double.
  • Since user input can be empty, so val can be empty, hence double.tryParse can return a null value. So, you use a null check operator(??) to assign _billAmount to 0 when the user input is empty.
  • After determining the _billAmount, you call the _updateAmounts function. It calculates the Tip Amount and Bill Amount and updates the UI of the app.

The same procedure applies to the working of the Tip Percentage text field.

Testing the App Manually

The coding part of your app is complete and the final step is to test whether it is doing the right calculations.

A good test covers some common use cases. You can test each of the below three test cases and make sure the app’s output matches the required output.

Bill Amount(Input)Tip Percentage(Input)Tip Amount(Output)Total Amount(Output)
01500
1001515115
1002020120

Before testing, make sure to use Hot Restart to build and run your app:

Flutter Tip Calculator App in Action

Congratulations! The app is showing accurate results. You are ready to use it when you go out for lunch and tip the waiter.

What’s Next?

In this tutorial, you learned about creating UI in Flutter, Stateless and Stateful widgets, Hot Reloading, managing state, and updating UI. You can add more features to your app, like a Number of Friends field, which you can use to divide the total amount between your friends.

📫

Loved this post? Join our Newsletter.

We write about React, Vue, Flutter, Strapi, Python and Automation. We don't spam.

Please add a valid email.
By clicking submit button, you agree to our privacy policy.
Thanks for subscribing to our newsletter.
There was some problem while registering your newsletter subscription. Please try again after some time or notify the owners at info@ravsam.in

ABOUT AUTHOR

Ravgeet Dhillon

Ravgeet is a Co-Founder and Developer at RavSam. He helps startups, businesses, open-source organizations with Digital Product Development and Technical Content Writing. He is a fan of Jamstack and likes to work with React, Vue, Flutter, Strapi, Node, Laravel and Python. He loves to play outdoor sports and cycles every day.

TAGGED WITH

Got a project or partnership in mind?

Let's Talk

Contact Us ->