Flutter 框架跨平台鸿蒙开发 - 计算器增强版
运行效果图本项目成功实现了一款功能完整、界面现代的计算器增强版应用,涵盖了工具类应用开发的核心要素。通过Flutter框架的应用,实现了跨平台的应用体验,证明了Flutter在工具类应用开发领域的可行性。项目采用模块化设计思想,将应用功能划分为表达式解析、科学计算、程序员计算、内存操作、历史记录等独立模块,各模块职责明确,耦合度低,便于维护和扩展。递归下降解析器:实现了完整的表达式解析,支持括号嵌
Flutter计算器增强版
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
项目概述
运行效果图



一、项目背景与目标
计算器是最基础也是最常用的工具类应用之一。从简单的四则运算到复杂的科学计算,计算器在日常生活、学习、工作中扮演着重要角色。本项目基于Flutter框架开发一款计算器增强版应用,不仅提供基本的四则运算功能,更集成了科学计算、程序员计算、进制转换等高级功能,打造一款功能全面、界面现代的计算工具。
项目的核心目标涵盖多个维度:构建完整的计算引擎系统,实现多种计算模式切换,设计直观的用户界面,打造流畅的交互体验,以及确保计算的准确性和性能表现。通过本项目的开发,不仅能够深入理解Flutter在工具类应用中的应用,更能掌握表达式解析、状态管理、键盘布局等核心技术要点。
二、技术选型与架构设计
技术栈分析
本项目选用Flutter作为开发框架,主要基于以下考量:Flutter的跨平台特性能够同时支持Android和iOS平台,降低开发成本;声明式UI编程范式能够高效构建复杂的键盘布局;丰富的Widget组件库为应用UI开发提供了坚实基础;优秀的性能表现确保了计算的流畅性。
Dart语言作为Flutter的开发语言,具备强类型、异步编程支持、优秀的性能表现等特性。项目采用单文件架构,将所有应用逻辑集中在main.dart文件中,这种设计既便于代码管理,又利于理解应用整体架构。
架构层次划分
应用架构采用分层设计思想,主要分为以下几个层次:
数据模型层:定义应用中的核心数据结构,包括CalculationHistory(计算历史)、CalculatorMode(计算模式)、NumberBase(进制类型)等类和枚举。这些模型类封装了计算器的状态和行为,构成了应用逻辑的基础。
业务逻辑层:实现应用的核心功能逻辑,包括表达式解析、数值计算、进制转换、内存操作等。这一层是应用的心脏,决定了应用的功能性和可用性。
渲染表现层:负责应用界面的绘制和UI展示,使用Flutter的Material Design组件库实现现代化的界面设计,通过动态键盘布局实现不同计算模式的切换。
状态管理层:管理应用的各种状态,包括当前显示值、表达式、计算模式、内存值等,确保应用状态的一致性和可预测性。
核心功能模块详解
一、表达式解析系统
解析器设计原理
表达式解析是计算器的核心功能,采用递归下降解析算法实现:
class _ExpressionParser {
int _pos = 0;
String _expr = '';
double parse(String expr) {
_expr = expr.replaceAll(' ', '');
_pos = 0;
return _parseExpression();
}
}
解析器维护当前位置指针_pos,从左到右扫描表达式。解析过程分为三个层次:表达式层处理加减法、项层处理乘除法、因子层处理数字和括号。
表达式层解析
表达式层处理加减运算:
double _parseExpression() {
double result = _parseTerm();
while (_pos < _expr.length) {
String op = _expr[_pos];
if (op == '+') {
_pos++;
result += _parseTerm();
} else if (op == '-') {
_pos++;
result -= _parseTerm();
} else {
break;
}
}
return result;
}
首先解析第一个项,然后循环处理后续的加减运算。这种设计确保了加减法的左结合性。
项层解析
项层处理乘除运算:
double _parseTerm() {
double result = _parseFactor();
while (_pos < _expr.length) {
String op = _expr[_pos];
if (op == '*') {
_pos++;
result *= _parseFactor();
} else if (op == '/') {
_pos++;
double divisor = _parseFactor();
if (divisor == 0) throw Exception('Division by zero');
result /= divisor;
} else {
break;
}
}
return result;
}
项层优先级高于表达式层,确保乘除法先于加减法执行。除法运算时检查除数是否为零,避免运行时错误。
因子层解析
因子层处理数字、括号和正负号:
double _parseFactor() {
if (_pos >= _expr.length) throw Exception('Unexpected end');
if (_expr[_pos] == '(') {
_pos++;
double result = _parseExpression();
if (_pos >= _expr.length || _expr[_pos] != ')') {
throw Exception('Missing )');
}
_pos++;
return result;
}
if (_expr[_pos] == '-') {
_pos++;
return -_parseFactor();
}
if (_expr[_pos] == '+') {
_pos++;
return _parseFactor();
}
return _parseNumber();
}
遇到左括号时递归解析括号内的表达式,遇到正负号时处理一元运算符。这种递归设计优雅地处理了嵌套括号的情况。
二、科学计算功能
三角函数实现
三角函数支持角度制输入:
case 'sin':
result = math.sin(value * math.pi / 180);
break;
case 'cos':
result = math.cos(value * math.pi / 180);
break;
case 'tan':
result = math.tan(value * math.pi / 180);
break;
用户输入的角度值需要转换为弧度制才能使用dart:math库的三角函数。转换公式为:弧度 = 角度 × π / 180。
对数函数实现
提供常用对数和自然对数:
case 'log':
result = math.log(value) / math.ln10;
break;
case 'ln':
result = math.log(value);
break;
dart:math库只提供自然对数log函数,常用对数通过换底公式计算:log₁₀(x) = ln(x) / ln(10)。
其他科学函数
case 'sqrt':
result = math.sqrt(value);
break;
case 'abs':
result = value.abs();
break;
case 'exp':
result = math.exp(value);
break;
case 'floor':
result = value.floorToDouble();
break;
case 'ceil':
result = value.ceilToDouble();
break;
平方根、绝对值、指数、取整等函数直接使用dart:math库实现,确保计算精度。
三、程序员计算功能
进制转换实现
进制转换使用Dart内置的进制转换函数:
String _convertBase(String value, NumberBase from, NumberBase to) {
try {
int decimal = int.parse(value, radix: _getRadix(from));
return decimal.toRadixString(_getRadix(to)).toUpperCase();
} catch (e) {
return 'Error';
}
}
int _getRadix(NumberBase base) {
switch (base) {
case NumberBase.binary:
return 2;
case NumberBase.octal:
return 8;
case NumberBase.decimal:
return 10;
case NumberBase.hexadecimal:
return 16;
}
}
int.parse函数支持指定进制解析字符串,toRadixString方法支持将整数转换为指定进制的字符串表示。
位运算支持
程序员模式支持多种位运算:
case 'AND':
case 'OR':
case 'XOR':
case 'NOT':
case 'MOD':
_insertOperator(value);
break;
case '<<':
case '>>':
_insertOperator(value);
break;
位运算符包括:与运算(AND)、或运算(OR)、异或运算(XOR)、非运算(NOT)、取模(MOD)、左移(<<)、右移(>>)。
四、内存操作功能
内存存储设计
计算器提供四个内存操作功能:
String _memory = '';
void _memoryClear() {
_memory = '';
}
void _memoryRecall() {
if (_memory.isNotEmpty) {
_display = _memory;
_isNewInput = true;
}
}
void _memoryAdd() {
try {
double current = double.parse(_display);
double mem = _memory.isEmpty ? 0 : double.parse(_memory);
_memory = _formatResult(mem + current);
} catch (e) {
_showError();
}
}
void _memorySubtract() {
try {
double current = double.parse(_display);
double mem = _memory.isEmpty ? 0 : double.parse(_memory);
_memory = _formatResult(mem - current);
} catch (e) {
_showError();
}
}
内存操作包括:MC(清除内存)、MR(调用内存)、M+(添加到内存)、M-(从内存减去)。内存值显示在屏幕底部,方便用户查看。
五、计算历史功能
历史记录存储
每次计算结果保存到历史列表:
class CalculationHistory {
final String expression;
final String result;
final DateTime timestamp;
}
_history.insert(0, CalculationHistory(
expression: _expression + _display,
result: formattedResult,
));
历史记录包含表达式、结果和时间戳,新记录插入到列表开头,确保最新的记录显示在最前面。
历史记录展示
历史页面使用列表展示所有记录:
ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: _history.length,
itemBuilder: (context, index) {
final item = _history[index];
return Card(
child: ListTile(
title: Text(item.expression),
subtitle: Text('= ${item.result}'),
trailing: Text(_formatTime(item.timestamp)),
onTap: () {
setState(() {
_display = item.result;
_isNewInput = true;
_currentIndex = 0;
});
},
),
);
},
)
点击历史记录可以将结果复制到当前显示,方便继续计算。
UI界面开发
一、主界面布局
主界面采用底部导航栏设计,包含三个主要页面:
BottomNavigationBar(
currentIndex: _currentIndex,
onTap: (index) => setState(() => _currentIndex = index),
selectedItemColor: Colors.teal,
unselectedItemColor: Colors.grey,
items: const [
BottomNavigationBarItem(icon: Icon(Icons.calculate), label: '计算器'),
BottomNavigationBarItem(icon: Icon(Icons.history), label: '历史'),
BottomNavigationBarItem(icon: Icon(Icons.transform), label: '转换'),
],
)
三个页面分别是计算器、历史记录和进制转换,覆盖了应用的主要功能入口。
二、显示区域设计
显示区域展示当前输入和表达式:
Widget _buildDisplay() {
return Container(
padding: const EdgeInsets.all(20),
color: Colors.grey.shade850,
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(_expression, style: TextStyle(color: Colors.grey.shade500, fontSize: 18)),
const SizedBox(height: 8),
Text(_display, style: TextStyle(color: _hasError ? Colors.red : Colors.white, fontSize: 48)),
if (_memory.isNotEmpty)
Row(
children: [
Icon(Icons.memory, size: 14, color: Colors.teal.shade300),
Text('M: $_memory', style: TextStyle(color: Colors.teal.shade300, fontSize: 12)),
],
),
],
),
);
}
显示区域分为三层:表达式层显示当前计算过程,结果层显示当前数值,内存层显示存储的内存值。错误时结果显示为红色。
三、键盘布局设计
基本模式键盘
基本模式提供四则运算和内存操作:
Widget _buildBasicKeyboard() {
return Container(
child: Column(
children: [
_buildKeyboardRow(['MC', 'MR', 'M+', 'M-']),
_buildKeyboardRow(['C', '⌫', '%', '÷']),
_buildKeyboardRow(['7', '8', '9', '×']),
_buildKeyboardRow(['4', '5', '6', '-']),
_buildKeyboardRow(['1', '2', '3', '+']),
_buildKeyboardRow(['±', '0', '.', '=']),
],
),
);
}
键盘采用网格布局,每行四个按钮。数字键使用灰色背景,运算符使用主题色背景,清除键使用红色背景。
科学模式键盘
科学模式扩展了科学计算功能:
Widget _buildScientificKeyboard() {
return SingleChildScrollView(
child: Column(
children: [
_buildKeyboardRow(['sin', 'cos', 'tan', '÷']),
_buildKeyboardRow(['log', 'ln', 'sqrt', '×']),
_buildKeyboardRow(['π', 'e', '^', '-']),
_buildKeyboardRow(['(', ')', '!', '+']),
_buildKeyboardRow(['C', '⌫', '%', '=']),
_buildKeyboardRow(['7', '8', '9', 'abs']),
_buildKeyboardRow(['4', '5', '6', 'exp']),
_buildKeyboardRow(['1', '2', '3', 'floor']),
_buildKeyboardRow(['±', '0', '.', 'ceil']),
],
),
);
}
科学模式键盘使用SingleChildScrollView包裹,支持滚动查看所有按钮。科学函数按钮使用紫色背景,与基本按钮区分。
程序员模式键盘
程序员模式提供进制选择和位运算:
Widget _buildProgrammerKeyboard() {
return Column(
children: [
_buildBaseSelector(),
_buildKeyboardRow(['AND', 'OR', 'XOR', 'NOT']),
_buildKeyboardRow(['<<', '>>', 'MOD', '÷']),
_buildKeyboardRow(['A', 'B', 'C', '×']),
_buildKeyboardRow(['D', 'E', 'F', '-']),
_buildKeyboardRow(['7', '8', '9', '+']),
_buildKeyboardRow(['4', '5', '6', '⌫']),
_buildKeyboardRow(['1', '2', '3', 'C']),
_buildKeyboardRow(['±', '0', '.', '=']),
],
);
}
程序员模式顶部显示进制选择器,支持二进制、八进制、十进制、十六进制切换。A-F按钮用于输入十六进制数字。
四、按钮样式设计
按钮根据功能类型使用不同颜色:
Widget _buildButton(String text) {
Color bgColor;
if (['÷', '×', '-', '+', '='].contains(text)) {
bgColor = Colors.teal;
} else if (['C', '⌫'].contains(text)) {
bgColor = Colors.red.shade400;
} else if (RegExp(r'^[0-9]$').hasMatch(text) || text == '.') {
bgColor = Colors.grey.shade800;
} else if (['sin', 'cos', 'tan', ...].contains(text)) {
bgColor = Colors.indigo.shade600;
} else if (['AND', 'OR', 'XOR', ...].contains(text)) {
bgColor = Colors.purple.shade600;
} else if (['MC', 'MR', 'M+', 'M-'].contains(text)) {
bgColor = Colors.orange.shade600;
} else {
bgColor = Colors.grey.shade700;
}
return Material(
color: bgColor,
borderRadius: BorderRadius.circular(12),
child: InkWell(
onTap: () => _onButtonPress(text),
child: Container(height: 60, child: Text(text)),
),
);
}
颜色编码帮助用户快速识别按钮功能:青色表示运算符,红色表示清除,灰色表示数字,紫色表示科学函数,橙色表示内存操作。
性能优化方案
一、表达式解析优化
解析器使用位置指针避免字符串复制:
double parse(String expr) {
_expr = expr.replaceAll(' ', '');
_pos = 0;
return _parseExpression();
}
只进行一次空格移除操作,后续解析直接在原字符串上进行,避免频繁的字符串复制。
二、状态管理优化
状态更新采用增量方式:
void _insertDigit(String digit) {
if (_isNewInput) {
_display = digit;
_isNewInput = false;
} else {
_display += digit;
}
}
数字输入时只在现有字符串后追加,避免重建整个字符串。状态标志位_isNewInput避免了不必要的判断。
三、列表渲染优化
历史列表使用ListView.builder实现按需渲染:
ListView.builder(
itemCount: _history.length,
itemBuilder: (context, index) {
return Card(...);
},
)
只有可见区域的历史记录才会被创建和渲染,大幅降低了内存占用。
测试方案与步骤
一、功能测试
基本运算测试:验证加减乘除四则运算是否正确;测试连续运算的优先级;检查括号运算是否正确。
科学计算测试:验证三角函数计算结果;测试对数函数计算精度;检查阶乘运算边界条件。
程序员模式测试:验证进制转换结果;测试位运算正确性;检查十六进制输入。
内存操作测试:验证内存存储和调用;测试内存加减运算;检查内存清除功能。
二、边界测试
除零测试:验证除以零时的错误处理。
溢出测试:测试大数计算的结果处理。
精度测试:验证浮点数计算的精度。
三、用户体验测试
响应速度测试:测试按钮响应的及时性。
界面美观测试:评估界面设计和颜色搭配。
操作便捷性测试:评估键盘布局的合理性。
项目总结与展望
一、项目成果总结
本项目成功实现了一款功能完整、界面现代的计算器增强版应用,涵盖了工具类应用开发的核心要素。通过Flutter框架的应用,实现了跨平台的应用体验,证明了Flutter在工具类应用开发领域的可行性。
项目采用模块化设计思想,将应用功能划分为表达式解析、科学计算、程序员计算、内存操作、历史记录等独立模块,各模块职责明确,耦合度低,便于维护和扩展。
二、技术亮点总结
递归下降解析器:实现了完整的表达式解析,支持括号嵌套和运算符优先级。
多模式切换:支持基本、科学、程序员三种计算模式,满足不同用户需求。
进制转换:支持二进制、八进制、十进制、十六进制的相互转换。
内存操作:提供完整的内存存储和操作功能。
计算历史:记录计算历史,支持快速调用历史结果。
三、未来优化方向
单位换算:添加长度、重量、温度等常用单位换算功能。
汇率转换:集成实时汇率API,支持货币转换。
语音输入:支持语音输入表达式,提升便捷性。
主题切换:支持多种主题颜色和布局风格。
小部件支持:添加桌面小部件,快速访问计算功能。
云同步:实现计算历史云端同步,多设备共享。
四、开发经验总结
通过本项目的开发,积累了宝贵的Flutter应用开发经验:
解析算法的重要性:表达式解析是计算器的核心,理解递归下降算法的原理,掌握运算符优先级处理,是开发此类应用的基础。
状态管理的简洁性:计算器涉及大量状态变化,简洁的状态管理设计能够确保数据的一致性和可预测性。
用户体验的细节:工具类应用最终服务于用户,从按钮的颜色编码到键盘的布局设计,每个细节都需要精心打磨。
功能扩展的灵活性:良好的架构设计使得功能扩展变得简单,从基本计算到科学计算再到程序员计算,模块化的设计确保了代码的可维护性。
本项目为Flutter工具类应用开发提供了一个完整的实践案例,展示了如何实现表达式解析、多模式切换、进制转换等核心功能,希望能够为相关开发者提供参考和启发,推动Flutter在工具类应用开发领域的应用和发展。
更多推荐



所有评论(0)