Mon, Jun 5, 2023
Read in 5 minutes
In this tutorial I will show you how to build a basic calculator app using Flutter step-by-step. With this tutorial you can enhance your Flutter skills and create your own custom calculator app with ease. We apply as many functionalities as possible, after completing this tutorial you can improve this app based on your preferences.
If you want the full explanation and code along with me, you can watch the full video tutorial here
First copy and paste the following code inside your main.dart file
import 'package:flutter/material.dart';
import 'calcualtor_screen.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Calculator',
debugShowCheckedModeBanner: false,
theme: ThemeData.dark(),
home: const CalculatorScreen(),
);
}
}
Then, create button_values.dart file and copy and paste the following code. This Btn class helps is a convenient class to use button values whenever we need them instead of hardcoding string values.
class Btn {
static const String del = "D";
static const String clr = "C";
static const String per = "%";
static const String multiply = "×";
static const String divide = "÷";
static const String add = "+";
static const String subtract = "-";
static const String calculate = "=";
static const String dot = ".";
static const String n0 = "0";
static const String n1 = "1";
static const String n2 = "2";
static const String n3 = "3";
static const String n4 = "4";
static const String n5 = "5";
static const String n6 = "6";
static const String n7 = "7";
static const String n8 = "8";
static const String n9 = "9";
static const List<String> buttonValues = [
del,
clr,
per,
multiply,
n7,
n8,
n9,
divide,
n4,
n5,
n6,
subtract,
n1,
n2,
n3,
add,
n0,
dot,
calculate,
];
}
Finally, create a calculator_screen.dart file and copy paste the following code. This StatefullWidget contains our Calculator App UI and all the functionalities.
import 'package:calculator/button_values.dart';
import 'package:flutter/material.dart';
class CalculatorScreen extends StatefulWidget {
const CalculatorScreen({super.key});
@override
State<CalculatorScreen> createState() => _CalculatorScreenState();
}
class _CalculatorScreenState extends State<CalculatorScreen> {
String number1 = ""; // . 0-9
String operand = ""; // + - * /
String number2 = ""; // . 0-9
@override
Widget build(BuildContext context) {
final screenSize = MediaQuery.of(context).size;
return Scaffold(
body: SafeArea(
bottom: false,
child: Column(
children: [
// output
Expanded(
child: SingleChildScrollView(
reverse: true,
child: Container(
alignment: Alignment.bottomRight,
padding: const EdgeInsets.all(16),
child: Text(
"$number1$operand$number2".isEmpty
? "0"
: "$number1$operand$number2",
style: const TextStyle(
fontSize: 48,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.end,
),
),
),
),
// buttons
Wrap(
children: Btn.buttonValues
.map(
(value) => SizedBox(
width: value == Btn.n0
? screenSize.width / 2
: (screenSize.width / 4),
height: screenSize.width / 5,
child: buildButton(value),
),
)
.toList(),
)
],
),
),
);
}
Widget buildButton(value) {
return Padding(
padding: const EdgeInsets.all(4.0),
child: Material(
color: getBtnColor(value),
clipBehavior: Clip.hardEdge,
shape: OutlineInputBorder(
borderSide: const BorderSide(
color: Colors.white24,
),
borderRadius: BorderRadius.circular(100),
),
child: InkWell(
onTap: () => onBtnTap(value),
child: Center(
child: Text(
value,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 24,
),
),
),
),
),
);
}
// ########
void onBtnTap(String value) {
if (value == Btn.del) {
delete();
return;
}
if (value == Btn.clr) {
clearAll();
return;
}
if (value == Btn.per) {
convertToPercentage();
return;
}
if (value == Btn.calculate) {
calculate();
return;
}
appendValue(value);
}
// ##############
// calculates the result
void calculate() {
if (number1.isEmpty) return;
if (operand.isEmpty) return;
if (number2.isEmpty) return;
final double num1 = double.parse(number1);
final double num2 = double.parse(number2);
var result = 0.0;
switch (operand) {
case Btn.add:
result = num1 + num2;
break;
case Btn.subtract:
result = num1 - num2;
break;
case Btn.multiply:
result = num1 * num2;
break;
case Btn.divide:
result = num1 / num2;
break;
default:
}
setState(() {
number1 = result.toStringAsPrecision(3);
if (number1.endsWith(".0")) {
number1 = number1.substring(0, number1.length - 2);
}
operand = "";
number2 = "";
});
}
// ##############
// converts output to %
void convertToPercentage() {
// ex: 434+324
if (number1.isNotEmpty && operand.isNotEmpty && number2.isNotEmpty) {
// calculate before conversion
calculate();
}
if (operand.isNotEmpty) {
// cannot be converted
return;
}
final number = double.parse(number1);
setState(() {
number1 = "${(number / 100)}";
operand = "";
number2 = "";
});
}
// ##############
// clears all output
void clearAll() {
setState(() {
number1 = "";
operand = "";
number2 = "";
});
}
// ##############
// delete one from the end
void delete() {
if (number2.isNotEmpty) {
// 12323 => 1232
number2 = number2.substring(0, number2.length - 1);
} else if (operand.isNotEmpty) {
operand = "";
} else if (number1.isNotEmpty) {
number1 = number1.substring(0, number1.length - 1);
}
setState(() {});
}
// #############
// appends value to the end
void appendValue(String value) {
// number1 opernad number2
// 234 + 5343
// if is operand and not "."
if (value != Btn.dot && int.tryParse(value) == null) {
// operand pressed
if (operand.isNotEmpty && number2.isNotEmpty) {
// TODO calculate the equation before assigning new operand
calculate();
}
operand = value;
}
// assign value to number1 variable
else if (number1.isEmpty || operand.isEmpty) {
// check if value is "." | ex: number1 = "1.2"
if (value == Btn.dot && number1.contains(Btn.dot)) return;
if (value == Btn.dot && (number1.isEmpty || number1 == Btn.n0)) {
// ex: number1 = "" | "0"
value = "0.";
}
number1 += value;
}
// assign value to number2 variable
else if (number2.isEmpty || operand.isNotEmpty) {
// check if value is "." | ex: number1 = "1.2"
if (value == Btn.dot && number2.contains(Btn.dot)) return;
if (value == Btn.dot && (number2.isEmpty || number2 == Btn.n0)) {
// number1 = "" | "0"
value = "0.";
}
number2 += value;
}
setState(() {});
}
// ########
Color getBtnColor(value) {
return [Btn.del, Btn.clr].contains(value)
? Colors.blueGrey
: [
Btn.per,
Btn.multiply,
Btn.add,
Btn.subtract,
Btn.divide,
Btn.calculate,
].contains(value)
? Colors.orange
: Colors.black87;
}
}
Now if you run your app on an emulator/real device you should have a calculator looking like the image you should have seen at the beginning of this page. Feel free modify and improve this app, and you can use it for any purpose you want. Thank you!