Support Ticket Why UserCV? [FAQ] Knowledgebase Personal Blogging Platform Start Teaching Online
Company is going under Migratiiion - Some of the functionalities may not be available for the time being.
Build simple Calculator using Flutter for Android mobile using Flutter Framework

If you wanted to understand little how-to on Flutter framework development, this is it. In this blog post, you will understand very basic overview of android app development using flutter.

Building Hybrid mobile application has become viral now. Most of the company now prefers Mobile app development using Hybrid technology like "Flutter, React Native, Native Scripts" and other.

Flutter is quite getting more famous now due to it's performance improvement over other technology. In this blog post, we will learn how to create basic Calculator app using Android and iOS mobile devices using flutter.

Prerequisite:

  • Knowledge of Dart lang
  • Android Studio IDE
  • flutter pre installed.

What we will not be covering?

  1. What is dart lang?
  2. What is Flutter?
  3. What is Android studio IDE?
  4. Flutter installation in your PC
  5. Android studio installation in your PC

We will not be covering any of above parts. I highly recommend to "Google", if you have any questions or need help anything related above 5 points. 

What we will be doing?

  1. We will be creating basic UI for our calculator app
  2. Validation of Form fields.
  3. Logic behind our calculator app.

Let's Start

Step 1: Launch Android Studio IDE

Step 2: Create New Flutter App using "Android Studio IDE"

  1. Choose "Flutter Application" from top as selected and Click "Next".
  2. Provide unique package name like "golang.usercv.com"
  3. Click "Finish"

Step 3: Start Coding

You will see lots of code in your "main.dart" file. I request you to delete all the existing code inside your "main.dart" file. Since, we will be building our own fresh application from scratch.

Once deleted, Let's Start. Our first line is to import "material design" to our code.

import 'package:flutter/material.dart';

Above package helps us provide "masterial design" look for our app. We know material design is widely used design for mobile devices. We are starting with same package too.

Let's Start our "main" function. Write below "import" code in your "main.dart" file.

void main() {
  runApp(MaterialApp(
    title: "Simple Interest Calculator App",
    home: CalculatorApp()
  );
}

Above is basic code, it won't do anything plus it will give you error too. Above is basic boilerplate for our app, that we will be developing.

We have added "MaterialApp" design and provided "title" to our App and pointed "home" named parameter to "CalculatorApp()"

If you are thinking, from where did "CalculatorApp" came from, well we have not coded that, we will be coding it next. 

Before, we start coding our CalculatorApp code, we need to do certain things like:

  • removing debug banner
  • setting up Theme

For that please replace above code with "below code"

void main() {
  runApp(MaterialApp(
    debugShowCheckedModeBanner: false,
    title: "Simple Interest Calculator App",
    home: CalculatorApp(),
    theme: ThemeData(
            brightness: Brightness.dark,
            primaryColor: Colors.deepOrange,
            accentColor: Colors.deepOrangeAccent
        ),
  ));
}

Oh! Lot happened? Well don't worry, I will explain them slowly.

  1. Line: `debugShowCheckedModeBanner` will help us get rid of "debug" banner inside our app, that we will be creating.
  2. "theme:" named parameter helps our "MobileApp" to customize our Mobile app for different color and design. We will be using "ThemeData" value for that, which offers various customization option like below:
    Brightness brightness,
    MaterialColor primarySwatch,
    Color primaryColor,
    Brightness primaryColorBrightness,
    Color primaryColorLight,
    Color primaryColorDark,
    Color accentColor,
    Brightness accentColorBrightness,
    Color canvasColor,
    Color scaffoldBackgroundColor,
    Color bottomAppBarColor,
    Color cardColor,
    Color dividerColor,
    Color highlightColor,
    Color splashColor,
    InteractiveInkFeatureFactory splashFactory,
    Color selectedRowColor,
    Color unselectedWidgetColor,
    Color disabledColor,
    Color buttonColor,
    ButtonThemeData buttonTheme,
    Color secondaryHeaderColor,
    Color textSelectionColor,
    Color cursorColor,
    Color textSelectionHandleColor,
    Color backgroundColor,
    Color dialogBackgroundColor,
    Color indicatorColor,
    Color hintColor,
    Color errorColor,
    Color toggleableActiveColor,
    String fontFamily,
    TextTheme textTheme,
    TextTheme primaryTextTheme,
    TextTheme accentTextTheme,
    InputDecorationTheme inputDecorationTheme,
    IconThemeData iconTheme,
    IconThemeData primaryIconTheme,
    IconThemeData accentIconTheme,
    SliderThemeData sliderTheme,
    TabBarTheme tabBarTheme,
    ChipThemeData chipTheme,
    TargetPlatform platform,
    MaterialTapTargetSize materialTapTargetSize,
    PageTransitionsTheme pageTransitionsTheme,
    ColorScheme colorScheme,
    DialogTheme dialogTheme,
    Typography typography,

You can find detail reference to UI theme design here - https://docs.flutter.io/flutter/material/ThemeData-class.html

It has detail documentation related to "ThemeData"

Let's move forward and create our "CalculatorApp" class

class CalculatorApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return _CalculatorAppState();
  }
}

Above, we just created "StatefulWidget" - CalculatorApp and we are returning "_CalculatorAppState()"

You might be thinking What is "StatefulWidget"?

In flutter, we have 2 state :-

  1. StatefulWidget
  2. StatelessWidget

Before, I give little introduction to what are they, we first need to understand, What is State?

State in framework like "Flutter" is basically element that can read synchronously from the time widget was built to it's lifetime of the widget while it has different value. That means, you may create some element or variable which value may change later during the lifetime of app. We call them state.

In other words in Flutter, "State" tells the property of our Widget inside app.

StatefulWidget extension helps our class to have dynamically changeable widget like "Checkbox, Radio, Textfields" etc.,  It is helpful when the part of our User Interface can change dynamically.

StatelessWidget extension helps our class to have non-mutable state widget like "logo image inside app", or any "non-dynamic hard coded text or links" etc., It is helpful when the part of our User Interface does not depend on anything other than the configuration information in the object itself and the BuildContext in which the widget is inflated.

You can read more about StatefulWidget and StatelessWidget here :-

  1. StatefulWidget: https://docs.flutter.io/flutter/widgets/StatefulWidget-class.html
  2. StatelessWidget: https://docs.flutter.io/flutter/widgets/StatelessWidget-class.html

Let's Jump into our Code again and create our "Mutable" state Class based on "StatefulWidget'. Since any class that inherits "StatefulWidget" are immutable, we need to return our data from "mutable" state. That's where our "_CalculatorApp" comes in.

import 'package:flutter/material.dart';
import 'package:validators/validators.dart';

void main() {
  runApp(MaterialApp(
    debugShowCheckedModeBanner: false,
    title: "Simple Interest Calculator App",
    home: CalculatorApp(),
    theme: ThemeData(
        primaryColor: Colors.deepOrange,
        accentColor: Colors.deepOrangeAccent,
        brightness: Brightness.dark),
  ));
}

class CalculatorApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return _CalculatorApp();
  }
}

class _CalculatorApp extends State<CalculatorApp> {
  @override
  Widget build(BuildContext context) {
    return null;
  }
}

Connect your Emulator and Click on "Build" and see your Fresh App with no Content or element in It. Let's Start Creating Element for our Calculator app:

We Need 3 form Field and we need to Keep Whole Form Field inside "Scaffold".

We can Create Scaffold like below:-

import 'package:flutter/material.dart';
import 'package:validators/validators.dart';

void main() {
  runApp(MaterialApp(
    debugShowCheckedModeBanner: false,
    title: "Simple Interest Calculator App",
    home: CalculatorApp(),
    theme: ThemeData(
        primaryColor: Colors.deepOrange,
        accentColor: Colors.deepOrangeAccent,
        brightness: Brightness.dark),
  ));
}

class CalculatorApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return _CalculatorApp();
  }
}

class _CalculatorApp extends State<CalculatorApp> {
  @override
  Widget build(BuildContext context) {
    return return Scaffold(
        appBar: AppBar(
          title: Text("Simple Interest Calculator"),
        ),
        body: Form()
    );
  }
}

We moved from return null to "Basic Scaffold" of our app inside our "_CalculatorApp", We created "Form()" in body, since we will have Form to get User's Input. For our Form, We need 3 input field as below:

  1. Principal Amount Input Field
  2. Rate of Interest Input Field
  3. Terms of Years Input Field

To Create FormField in Flutter, we use following Code:

TextFormField(
  keyboardType: TextInputType.number, // this open "Number only" Keyboard for typing
  validator: (String value) {
    if (value.isEmpty) {
      return "Value can not be Empty"
    }
  },
  decoration: InputDecoration(
    labelText: "Form Field",
    hintText: "Placeholder text",
    errorStyle: TextStyle(
      color: Colors.yellowAccent,
      fontSize: 15.0
    ),
    border: OutlineInputBorder(
      borderRadius:
      BorderRadius.circular(5.0)
    )
  ),
),

Since, we need 3 Form Field, We will create 3 TextFormField like above.

But, before we can create any form field, we need some decoration for our app. 

  1. Like Image on Top
  2. Some Padding between Form fields and Container
  3. 2 Button for "Calculate" and "Reset".
  4. Result placeholder, where our result will be displayed.

Whenever we create "Form", It's important to "create" FormKey to differentiate between multiple forms in UI. It is more important to "Validate" our data provided by User.

For Validation, I highly recommend "Validators" package. Checkout here - https://pub.dartlang.org/packages/validators

We will be using above Validator package, So, Let's Prepate our Project for 2 things :-

  1. Image stuff
  2. Validator Package

To do above thing, we need to modify our "pubspec.yaml" file located in our project directory and add following code:

  1. Just below "dependencies:" inside "pubspec.yaml" file, add code like below:

    dependencies:
      flutter:
        sdk: flutter
      validators: ^1.0.0+1.  // This line should be added or different version based on your reading date and time.​
  2. We need to create "images" directory in our "Flutter Project app", So Create "images" directory/folder in your project app
  3. Find and Comment out "images" code from "pubspec.yaml" file like below, You will have to uncomment only "assets:" and add your image file like below.

    flutter:
    
      # The following line ensures that the Material Icons font is
      # included with your application, so that you can use the icons in
      # the material Icons class.
      uses-material-design: true
    
      # To add assets to your application, add an assets section, like this:
      
      assets:
        - images/money.jpg​
  4. Now, Download any "money.jpg" file from internet and store it inside your "images directory" or your "Flutter Project".

It is important that you download file and store it inside images folder. 

Remember: if you have different file name, make sure you provide same name in your "pubspec.yaml" file.

Now, Once you have added your "validator" package, you need to Click on "Packages Get" menu popped up on top of your "pubspec.yaml" file, or you can execute below command in terminal from your flutter project directory to download "validator" package:

flutter packages get

Once the package has been downloaded, you are ready to import and use it in our Code. Sometimes package import may give error, so you can just "restart" your AndroidStudio and open your flutter project back.

When done all above. Just Copy and Paste below Code into your package and Your app is ready:

import 'package:flutter/material.dart';
import 'package:validators/validators.dart';

void main() {
    runApp(MaterialApp(
        debugShowCheckedModeBanner: false,
        title: "Simple Interest Calculator App",
        home: CalculatorApp(),
        theme: ThemeData(
            primaryColor: Colors.deepOrange,
            accentColor: Colors.deepOrangeAccent
        ),
    ));
}

class CalculatorApp extends StatefulWidget {
    @override
    State<StatefulWidget> createState() {
        // TODO: implement createState
        return _CalculatorApp();
    }
}

class _CalculatorApp extends State<CalculatorApp> {

    var _formKey = GlobalKey<FormState>();

    final _minimumPadding = 5.0;

    var displayResult = 'Results will be displayed here...';

    bool _autoValidate = false;

    TextEditingController principalController = TextEditingController();
    TextEditingController roiController = TextEditingController();
    TextEditingController termController = TextEditingController();

    @override
    Widget build(BuildContext context) {
        TextStyle textStyle = Theme.of(context).textTheme.title;

        return Scaffold(
            appBar: AppBar(
                title: Text("Simple Interest Calculator App"),
            ),
            body: Form(
                key: _formKey,
                autovalidate: _autoValidate,
                child: Padding(
                    padding: EdgeInsets.all(_minimumPadding * 2),
                    child: ListView(
                        children: <Widget>[
                            getImageAsset(),
                            Padding(
                                padding: EdgeInsets.all(_minimumPadding * 2),
                                child: TextFormField(
                                    keyboardType: TextInputType.number,
                                    style: textStyle,
                                    controller: principalController,
                                    validator: (String value) {
                                        if (value.isEmpty) {
                                            return 'Please enter principal amount';
                                        }
                                        if (!isNumeric(value)) {
                                            return 'Please enter numbers only';
                                        }
                                    },
                                    decoration: InputDecoration(
                                        labelText: "Principal Amount",
                                        labelStyle: textStyle,
                                        hintText: "Enter Principal e.g, 100000",
                                        errorStyle: TextStyle(
                                            fontSize: 15.0,
                                        ),
                                        border: OutlineInputBorder(
                                            borderRadius: BorderRadius.circular(5.0))),
                                ),
                            ),
                            Padding(
                                padding: EdgeInsets.all(_minimumPadding * 2),
                                child: TextFormField(
                                    keyboardType: TextInputType.number,
                                    style: textStyle,
                                    controller: roiController,
                                    validator: (String value) {
                                        if (value.isEmpty) {
                                            return 'Please enter rate of interest';
                                        }
                                    },
                                    decoration: InputDecoration(
                                        labelText: "Rate of Interest",
                                        labelStyle: textStyle,
                                        hintText: "Enter Rate e.g, 5",
                                        errorStyle: TextStyle(
                                            fontSize: 15.0,
                                        ),
                                        border: OutlineInputBorder(
                                            borderRadius: BorderRadius.circular(5.0))),
                                ),
                            ),
                            Padding(
                                padding: EdgeInsets.all(_minimumPadding * 2),
                                child: TextFormField(
                                    keyboardType: TextInputType.number,
                                    style: textStyle,
                                    controller: termController,
                                    validator: (String value) {
                                        if (value.isEmpty) {
                                            termController.text = "1";
                                        }
                                    },
                                    decoration: InputDecoration(
                                        labelText: "Term",
                                        labelStyle: textStyle,
                                        hintText: "Time in Years",
                                        errorStyle: TextStyle(
                                            fontSize: 15.0),
                                        border: OutlineInputBorder(
                                            borderRadius:
                                            BorderRadius.circular(5.0))
                                    ),
                                )
                            ),
                            Padding(
                                padding: EdgeInsets.all(_minimumPadding * 2),
                                child: Row(
                                    children: <Widget>[
                                        Expanded(
                                            child: Padding(
                                                padding:
                                                EdgeInsets.only(right: _minimumPadding * 2),
                                                child: RaisedButton(
                                                    color: Theme.of(context).accentColor,
                                                    textColor: Theme.of(context).primaryColorLight,
                                                    onPressed: () {
                                                        setState(() {
                                                            if (_formKey.currentState.validate()) {
                                                                this.displayResult = _calculateResult();
                                                            } else {
                                                                _autoValidate = true;
                                                            }
                                                        });
                                                    },
                                                    child: Text(
                                                        "Calculate",
                                                        textScaleFactor: 1.5,
                                                    ),
                                                ),
                                            ),
                                        ),
                                        Expanded(
                                            child: Padding(
                                                padding: EdgeInsets.only(left: _minimumPadding * 2),
                                                child: RaisedButton(
                                                    color: Theme.of(context).primaryColorDark,
                                                    textColor: Theme.of(context).primaryColorLight,
                                                    onPressed: () {
                                                        setState(() {
                                                            _resetTextFields();
                                                        });
                                                    },
                                                    child: Text(
                                                        "Reset",
                                                        textScaleFactor: 1.5,
                                                    ),
                                                ),
                                            ),
                                        )
                                    ],
                                )),
                            Padding(
                                padding: EdgeInsets.all(_minimumPadding * 2),
                                child: Center(
                                    child: Text(
                                        this.displayResult,
                                        style: textStyle,
                                    ),
                                ),
                            )
                        ],
                    ),
                ),
            ));
    }

    Widget getImageAsset() {
        AssetImage assetImage = AssetImage("images/money.jpg");
        Image image = Image(image: assetImage, width: 125.0, height: 125.0);
        return Container(
            child: image,
            margin: EdgeInsets.all(_minimumPadding),
        );
    }

    String _calculateResult() {
        double principalAmt = double.parse(principalController.text);
        double roiAmt = double.parse(roiController.text);
        double termAmt = double.parse(termController.text);

        double calculate = principalAmt + (principalAmt * roiAmt * termAmt) / 100;

        String result =
            'After $termAmt years, your investment will be worth $calculate';

        return result;
    }

    void _resetTextFields() {
        principalController.text = "";
        roiController.text = "";
        termController.text = "";
        displayResult = 'New result will be displayed here...';
    }
}

If you have any question on above, Feel free to ask them in below comment:

Cheers - Happy Coding.


Tags: mobile calculator app flutter development hybrid mobile app development android studio


acebook
About the Author
Comments
Show some love!
Liked It ? Share this Post
My recent posts