目录
[1. 运行效果图](#1. 运行效果图)
[1. 安装Flutter SDK](#1. 安装Flutter SDK)
[2. 安装鸿蒙开发环境](#2. 安装鸿蒙开发环境)
[3. 配置Flutter鸿蒙支持](#3. 配置Flutter鸿蒙支持)
[1. 应用入口](#1. 应用入口)
[2. 状态管理](#2. 状态管理)
[3. 数字输入处理](#3. 数字输入处理)
[4. 运算符处理](#4. 运算符处理)
[5. 计算逻辑](#5. 计算逻辑)
[6. 功能按钮实现](#6. 功能按钮实现)
[7. UI界面设计](#7. UI界面设计)
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
项目简介
本文介绍如何使用Flutter开发一个功能完善的计算器应用,该应用可以部署在鸿蒙系统上运行。计算器具备以下功能:
-
基本运算:加、减、乘、除
-
百分比计算
-
正负号切换
-
清除功能
-
小数点支持
1. 运行效果图

2.完整代码预览
Dart
import 'package:flutter/material.dart';
void main() {
runApp(const CalculatorApp());
}
class CalculatorApp extends StatelessWidget {
const CalculatorApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter鸿蒙计算器',
debugShowCheckedModeBanner: false,
theme: ThemeData(useMaterial3: true),
home: const Calculator(),
);
}
}
class Calculator extends StatefulWidget {
const Calculator({super.key});
@override
State<Calculator> createState() => _CalculatorState();
}
class _CalculatorState extends State<Calculator> {
String _display = '0';
String _previousValue = '';
String _operator = '';
bool _shouldResetDisplay = false;
bool _justCalculated = false;
String _formatResult(double value) {
if (value.isInfinite || value.isNaN) return '错误';
if (value == value.toInt() && value.abs() < 1e10) {
return value.toInt().toString();
}
String str = value.toStringAsFixed(8);
// 移除末尾的0和小数点
while (str.contains('.') && (str.endsWith('0') || str.endsWith('.'))) {
str = str.substring(0, str.length - 1);
}
return str;
}
void _onNumberPressed(String number) {
setState(() {
if (_justCalculated) {
_display = number;
_previousValue = '';
_operator = '';
_justCalculated = false;
_shouldResetDisplay = false;
return;
}
if (_shouldResetDisplay) {
_display = number;
_shouldResetDisplay = false;
} else {
if (number == '.' && _display.contains('.')) return;
if (_display == '0' && number != '.') {
_display = number;
} else {
_display += number;
}
}
});
}
void _onOperatorPressed(String op) {
setState(() {
_justCalculated = false;
if (_operator.isNotEmpty &&
!_shouldResetDisplay &&
_previousValue.isNotEmpty) {
_performCalculation();
}
_previousValue = _display;
_operator = op;
_shouldResetDisplay = true;
});
}
void _performCalculation() {
if (_previousValue.isEmpty || _operator.isEmpty) return;
try {
double num1 = double.parse(_previousValue);
double num2 = double.parse(_display);
double result = 0;
switch (_operator) {
case '+':
result = num1 + num2;
case '-':
result = num1 - num2;
case '×':
result = num1 * num2;
case '÷':
if (num2 == 0) {
_display = '错误';
_operator = '';
_previousValue = '';
return;
}
result = num1 / num2;
}
_display = _formatResult(result);
_previousValue = _display;
} catch (e) {
_display = '错误';
_operator = '';
_previousValue = '';
}
}
void _onEqualPressed() {
if (_operator.isEmpty || _previousValue.isEmpty) return;
setState(() {
_performCalculation();
_operator = '';
_previousValue = '';
_shouldResetDisplay = true;
_justCalculated = true;
});
}
void _onClearPressed() {
setState(() {
_display = '0';
_previousValue = '';
_operator = '';
_shouldResetDisplay = false;
_justCalculated = false;
});
}
void _onPercentagePressed() {
setState(() {
try {
double value = double.parse(_display);
_display = _formatResult(value / 100);
} catch (e) {
_display = '错误';
}
});
}
void _onToggleSignPressed() {
setState(() {
if (_display != '0' && _display != '错误') {
if (_display.startsWith('-')) {
_display = _display.substring(1);
} else {
_display = '-$_display';
}
}
});
}
Widget _buildButton({
required String text,
required VoidCallback onPressed,
Color? bgColor,
Color? textColor,
int flex = 1,
}) {
final isOperator = ['÷', '×', '-', '+', '='].contains(text);
final isSelected =
isOperator && text != '=' && _operator == text && _shouldResetDisplay;
return Expanded(
flex: flex,
child: Padding(
padding: const EdgeInsets.all(6),
child: Material(
color:
isSelected ? Colors.white : (bgColor ?? const Color(0xFF333333)),
borderRadius: BorderRadius.circular(100),
child: InkWell(
onTap: onPressed,
borderRadius: BorderRadius.circular(100),
child: AspectRatio(
aspectRatio: flex.toDouble(),
child: Center(
child: Text(
text,
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.w400,
color: isSelected
? const Color(0xFFFF9500)
: (textColor ?? Colors.white),
),
),
),
),
),
),
),
);
}
@override
Widget build(BuildContext context) {
const orange = Color(0xFFFF9500);
const gray = Color(0xFFA5A5A5);
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title:
const Text('Flutter鸿蒙计算器', style: TextStyle(color: Colors.white)),
backgroundColor: Colors.black,
centerTitle: true,
),
body: SafeArea(
child: Column(
children: [
Expanded(
flex: 2,
child: Container(
padding:
const EdgeInsets.symmetric(horizontal: 24, vertical: 16),
alignment: Alignment.bottomRight,
child: FittedBox(
fit: BoxFit.scaleDown,
child: Text(
_display,
style: const TextStyle(
fontSize: 80,
color: Colors.white,
fontWeight: FontWeight.w300),
),
),
),
),
Expanded(
flex: 5,
child: Padding(
padding: const EdgeInsets.all(8),
child: Column(
children: [
Expanded(
child: Row(children: [
_buildButton(
text: 'C',
onPressed: _onClearPressed,
bgColor: gray,
textColor: Colors.black),
_buildButton(
text: '±',
onPressed: _onToggleSignPressed,
bgColor: gray,
textColor: Colors.black),
_buildButton(
text: '%',
onPressed: _onPercentagePressed,
bgColor: gray,
textColor: Colors.black),
_buildButton(
text: '÷',
onPressed: () => _onOperatorPressed('÷'),
bgColor: orange),
])),
Expanded(
child: Row(children: [
_buildButton(
text: '7', onPressed: () => _onNumberPressed('7')),
_buildButton(
text: '8', onPressed: () => _onNumberPressed('8')),
_buildButton(
text: '9', onPressed: () => _onNumberPressed('9')),
_buildButton(
text: '×',
onPressed: () => _onOperatorPressed('×'),
bgColor: orange),
])),
Expanded(
child: Row(children: [
_buildButton(
text: '4', onPressed: () => _onNumberPressed('4')),
_buildButton(
text: '5', onPressed: () => _onNumberPressed('5')),
_buildButton(
text: '6', onPressed: () => _onNumberPressed('6')),
_buildButton(
text: '-',
onPressed: () => _onOperatorPressed('-'),
bgColor: orange),
])),
Expanded(
child: Row(children: [
_buildButton(
text: '1', onPressed: () => _onNumberPressed('1')),
_buildButton(
text: '2', onPressed: () => _onNumberPressed('2')),
_buildButton(
text: '3', onPressed: () => _onNumberPressed('3')),
_buildButton(
text: '+',
onPressed: () => _onOperatorPressed('+'),
bgColor: orange),
])),
Expanded(
child: Row(children: [
_buildButton(
text: '0',
onPressed: () => _onNumberPressed('0'),
flex: 2),
_buildButton(
text: '.', onPressed: () => _onNumberPressed('.')),
_buildButton(
text: '=',
onPressed: _onEqualPressed,
bgColor: orange),
])),
],
),
),
),
],
),
),
);
}
}
一、开发环境准备
1. 安装Flutter SDK
- 下载Flutter SDK并配置环境变量
- 运行 `flutter doctor` 检查开发环境
2. 安装鸿蒙开发环境
- 安装DevEco Studio
- 配置鸿蒙SDK和模拟器
3. 配置Flutter鸿蒙支持
- 启用Flutter鸿蒙平台支持
- 配置编译工具链
二、项目结构
项目采用单文件结构,主要代码集中在 `main.dart` 文件中:
lib/
└── main.dart # 主应用文件
三、核心代码实现
1. 应用入口
Dart
void main() {
runApp(const CalculatorApp());
}
class CalculatorApp extends StatelessWidget {
const CalculatorApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter鸿蒙计算器',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
),
home: const Calculator(),
);
}
}
2. 状态管理
计算器使用StatefulWidget来管理状态:
Dart
class Calculator extends StatefulWidget {
const Calculator({super.key});
@override
State<Calculator> createState() => _CalculatorState();
}
class _CalculatorState extends State<Calculator> {
String _display = '0'; // 显示的内容
String _previousValue = ''; // 之前的数值
String _operator = ''; // 操作符
bool _shouldResetDisplay = false; // 是否重置显示
3. 数字输入处理
Dart
void _onNumberPressed(String number) {
setState(() {
if (_shouldResetDisplay) {
_display = number;
_shouldResetDisplay = false;
} else {
if (_display == '0' && number != '.') {
_display = number;
} else if (number == '.' && _display.contains('.')) {
return;
} else {
_display += number;
}
}
});
}
功能说明:
- 当输入新数字时,如果需要重置则直接替换显示内容
- 防止多个小数点输入
- 自动处理0开头的数字
4. 运算符处理
Dart
void _onOperatorPressed(String operator) {
setState(() {
if (_previousValue.isEmpty) {
_previousValue = _display;
} else if (_operator.isNotEmpty && !_shouldResetDisplay) {
_calculate();
}
_operator = operator;
_shouldResetDisplay = true;
});
}
功能说明:
- 首次按下运算符时保存当前数值
- 连续运算时自动计算中间结果
- 设置运算符并标记下一次输入需要重置
5. 计算逻辑
Dart
void _calculate() {
if (_previousValue.isEmpty || _operator.isEmpty) return;
double num1 = double.parse(_previousValue);
double num2 = double.parse(_display);
double result = 0;
switch (_operator) {
case '+':
result = num1 + num2;
break;
case '-':
result = num1 - num2;
break;
case '×':
result = num1 * num2;
break;
case '÷':
if (num2 != 0) {
result = num1 / num2;
} else {
_display = '错误';
_operator = '';
_previousValue = '';
return;
}
break;
}
setState(() {
_display = result.toStringAsFixed(10).replaceAll(RegExp(r'\.?0+$'), '');
_previousValue = '';
_operator = '';
_shouldResetDisplay = true;
});
}
功能说明:
- 支持四则运算
- 除零错误处理
- 自动去除结果末尾多余的0
- 计算完成后重置状态
6. 功能按钮实现
清除功能
Dart
void _onClearPressed() {
setState(() {
_display = '0';
_previousValue = '';
_operator = '';
_shouldResetDisplay = false;
});
}
百分比计算
Dart
void _onPercentagePressed() {
setState(() {
double value = double.parse(_display);
_display = (value / 100).toString();
});
}
正负号切换
Dart
void _onToggleSignPressed() {
setState(() {
if (_display != '0') {
if (_display.startsWith('-')) {
_display = _display.substring(1);
} else {
_display = '-$_display';
}
}
});
}
7. UI界面设计
按钮组件
Dart
Widget _buildButton({
required String text,
required VoidCallback onPressed,
Color? backgroundColor,
Color? textColor,
}) {
return Container(
margin: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: onPressed,
style: ElevatedButton.styleFrom(
backgroundColor: backgroundColor ?? Colors.grey[300],
foregroundColor: textColor ?? Colors.black87,
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
minimumSize: const Size(80, 80),
),
child: Text(
text,
style: const TextStyle(
fontSize: 32,
fontWeight: FontWeight.w500,
),
),
),
);
}
设计要点:
- 圆角按钮设计
- 统一的按钮尺寸
- 可自定义的背景色和文字颜色
- 合适的边距和字体大小
界面布局
Dart
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
appBar: AppBar(
title: const Text(
'Flutter鸿蒙计算器',
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.black,
elevation: 0,
centerTitle: true,
),
body: Column(
children: [
// 显示屏
Expanded(
child: Container(
padding: const EdgeInsets.all(24),
alignment: Alignment.bottomRight,
child: Text(
_display,
style: TextStyle(
fontSize: _display.length > 9 ? 48 : 72,
color: Colors.white,
fontWeight: FontWeight.w300,
),
),
),
),
// 键盘区域
Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
// 5行按钮布局
// 第一行: C ± % ÷
// 第二行: 7 8 9 ×
// 第三行: 4 5 6 -
// 第四行: 1 2 3 +
// 第五行: 0 . =
],
),
),
],
),
);
}
设计特点:
- 黑色主题,符合现代计算器设计风格
- 自适应字体大小,长数字自动缩小
- 运算符使用橙色突出显示
- 功能键使用灰色区分
- 数字键使用深灰色,白字显示
四、总结
通过本教程,我们成功开发了一个功能完善的Flutter鸿蒙计算器应用。该项目展示了:
- Flutter在鸿蒙平台的强大支持
- Stateful Widget的状态管理
- Material Design的UI实现
- 基本算法逻辑的封装
项目代码结构清晰,易于理解和扩展,适合作为Flutter学习的入门项目。