Flutter for OpenHarmony 实战:投票管理系统完整开发指南
文章目录
- [Flutter for OpenHarmony 实战:投票管理系统完整开发指南](#Flutter for OpenHarmony 实战:投票管理系统完整开发指南)
-
- 摘要
- 一、项目背景与功能概述
-
- [1.1 投票系统的应用场景](#1.1 投票系统的应用场景)
- [1.2 应用功能规划](#1.2 应用功能规划)
- [1.3 投票规则说明](#1.3 投票规则说明)
- 二、投票系统设计原则
-
- [2.1 用户界面设计](#2.1 用户界面设计)
- [2.2 数据流向设计](#2.2 数据流向设计)
- 三、技术选型与架构设计
-
- [3.1 核心技术栈](#3.1 核心技术栈)
- [3.2 应用架构](#3.2 应用架构)
- [3.3 状态管理设计](#3.3 状态管理设计)
- 四、数据模型设计
-
- [4.1 候选人数据类](#4.1 候选人数据类)
- [4.2 选择状态管理](#4.2 选择状态管理)
- 五、候选人管理界面
-
- [5.1 界面布局设计](#5.1 界面布局设计)
- [5.2 候选人解析逻辑](#5.2 候选人解析逻辑)
- [5.3 取消按钮功能](#5.3 取消按钮功能)
- [5.4 投票规则说明](#5.4 投票规则说明)
- 六、投票界面实现
-
- [6.1 候选人列表](#6.1 候选人列表)
- [6.2 复选框状态管理](#6.2 复选框状态管理)
- 七、统计信息展示
-
- [7.1 统计卡片设计](#7.1 统计卡片设计)
- [7.2 统计信息布局](#7.2 统计信息布局)
- [7.3 操作按钮区域](#7.3 操作按钮区域)
- 八、完整代码实现
-
- [8.1 投票提交逻辑](#8.1 投票提交逻辑)
- [8.2 排序功能](#8.2 排序功能)
- [8.3 刷新重置功能](#8.3 刷新重置功能)
- 九、运行效果与测试
-
- [9.1 项目运行命令](#9.1 项目运行命令)
- [9.2 功能测试清单](#9.2 功能测试清单)
- 十、总结
- 十、总结
摘要

投票管理系统是各类组织和活动中必不可少的应用工具。本文将详细介绍如何使用Flutter for OpenHarmony框架开发一款功能完整的投票管理系统。文章涵盖了复选框状态管理、选票验证逻辑、实时统计、数据排序等核心技术点。通过本文学习,读者将掌握Flutter在鸿蒙平台上开发交互式应用的方法,了解如何构建功能完善、用户友好的投票应用。
一、项目背景与功能概述
1.1 投票系统的应用场景
投票系统广泛应用于:
- 班级干部选举
- 公司决策投票
- 活动评选
- 意见调查
- 民主评议
1.2 应用功能规划
| 功能模块 | 具体功能 |
|---|---|
| 候选人管理 | 输入候选人名单、确认、取消 |
| 投票功能 | 复选框选择、确定投票、刷新重置 |
| 选票验证 | 最多选3人、超过作废、不选为弃权 |
| 实时统计 | 总票数、有效票、废票、弃权票 |
| 排序功能 | 按票数排序显示候选人 |
1.3 投票规则说明
- 每张选票最多可选择3位候选人
- 选择超过3人,该票作废
- 不选择任何候选人,视为弃权
- 点击复选框选中/取消选中候选人
二、投票系统设计原则
2.1 用户界面设计
简洁性原则
- 候选人设置阶段:清晰的多行输入框
- 投票阶段:直观的复选框列表
- 统计阶段:醒目的统计卡片
一致性原则
- 颜色编码:绿色-有效票、红色-废票、灰色-弃权
- 按钮样式统一
- 交互反馈一致
2.2 数据流向设计

三、技术选型与架构设计
3.1 核心技术栈
状态管理
- StatefulWidget管理组件状态
- setState更新UI
- Set数据结构存储选中状态
UI组件
- TextField:候选人输入
- CheckboxListTile:复选框列表
- Card:统计卡片展示
- ListView:候选人列表
数据处理
- 正则表达式解析候选人
- 集合操作处理选择状态
- 排序算法实现票数排序
3.2 应用架构
VotingSystemApp (应用根组件)
└── VotingSystemPage (投票系统页面)
├── AppBar (导航栏 + 刷新按钮)
├── 候选人设置界面
│ ├── 输入提示
│ ├── 多行输入框
│ ├── 确认/取消按钮
│ └── 投票规则说明
└── 投票界面
├── 候选人列表(复选框)
└── 统计信息区域
├── 统计卡片(4个)
└── 操作按钮(投票、排序)
3.3 状态管理设计
dart
class _VotingSystemPageState extends State<VotingSystemPage> {
final List<Candidate> _candidates = []; // 候选人列表
final Set<String> _selectedCandidates = {}; // 选中的候选人
final TextEditingController _controller = TextEditingController();
int _totalVotes = 0; // 总选票数
int _invalidVotes = 0; // 废票数
int _abstainedVotes = 0; // 弃权票数
bool _isVotingMode = false; // 是否处于投票模式
}
四、数据模型设计
4.1 候选人数据类
dart
class Candidate {
String name; // 候选人姓名
int votes; // 得票数
Candidate({required this.name, this.votes = 0});
}
设计要点
- name:候选人唯一标识
- votes:初始值为0,投票时累加
4.2 选择状态管理
使用Set数据结构存储选中的候选人:
dart
final Set<String> _selectedCandidates = {};
Set的优势
- 自动去重
- 高效查找
- 方便添加/删除
五、候选人管理界面

5.1 界面布局设计
dart
Widget _buildSetupInterface() {
return Padding(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text('设置候选人名单'),
const SizedBox(height: 16),
const Text('请输入候选人姓名,用逗号或空格分隔'),
const SizedBox(height: 16),
TextField(
controller: _candidatesController,
maxLines: 5,
decoration: const InputDecoration(
labelText: '候选人名单',
hintText: '例如:张三, 李四, 王五, 赵六',
border: OutlineInputBorder(),
),
),
// 按钮...
],
),
);
}
5.2 候选人解析逻辑
dart
void _confirmCandidates() {
final text = _candidatesController.text.trim();
if (text.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('请输入候选人名单')),
);
return;
}
// 按逗号或空格分隔
final names = text.split(RegExp('[,,\\s]+'));
final validNames = names.where((name) => name.trim().isNotEmpty).toList();
if (validNames.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('候选人名单不能为空')),
);
return;
}
setState(() {
_candidates.clear();
for (var name in validNames) {
_candidates.add(Candidate(name: name.trim()));
}
_isVotingMode = true;
_resetStatistics();
});
}
解析规则
- 支持中英文逗号分隔
- 支持空格分隔
- 自动过滤空字符串
- 去除首尾空格
5.3 取消按钮功能
dart
void _cancelCandidates() {
_candidatesController.clear();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('已清空输入')),
);
}
5.4 投票规则说明
使用Card组件展示投票规则:
dart
Card(
color: Colors.blue.shade50,
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(Icons.info_outline, color: Colors.blue),
const SizedBox(width: 8),
const Text('投票规则'),
],
),
const SizedBox(height: 12),
const Text('• 每张选票最多可选3人'),
const Text('• 选择超过3人视为废票'),
const Text('• 不选择任何候选人视为弃权'),
const Text('• 点击复选框进行投票'),
],
),
),
)
六、投票界面实现
6.1 候选人列表
使用ListView.builder + CheckboxListTile:
dart
Expanded(
child: ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: _candidates.length,
itemBuilder: (context, index) {
final candidate = _candidates[index];
final isSelected = _selectedCandidates.contains(candidate.name);
return Card(
margin: const EdgeInsets.only(bottom: 12),
child: CheckboxListTile(
title: Text(
candidate.name,
style: const TextStyle(fontSize: 18),
),
subtitle: Text('得票: ${candidate.votes}'),
value: isSelected,
onChanged: (bool? value) {
setState(() {
if (value == true) {
_selectedCandidates.add(candidate.name);
} else {
_selectedCandidates.remove(candidate.name);
}
});
},
controlAffinity: ListTileControlAffinity.leading,
contentPadding: const EdgeInsets.all(16),
),
);
},
),
)
CheckboxListTile属性
- title:候选人姓名
- subtitle:当前得票数
- value:是否选中
- onChanged:选中状态变化回调
- controlAffinity:复选框位置(左侧)
6.2 复选框状态管理
dart
onChanged: (bool? value) {
setState(() {
if (value == true) {
_selectedCandidates.add(candidate.name);
} else {
_selectedCandidates.remove(candidate.name);
}
});
}
状态更新流程
- 用户点击复选框
- 触发onChanged回调
- 更新_selectedCandidates集合
- 调用setState刷新UI
- 重新渲染显示新状态
七、统计信息展示
7.1 统计卡片设计
dart
Widget _buildStatCard(String title, String value, Color color) {
return Expanded(
child: Card(
color: color,
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
children: [
Text(
title,
style: const TextStyle(
fontSize: 12,
color: Colors.white,
),
),
const SizedBox(height: 4),
Text(
value,
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
),
),
),
);
}
7.2 统计信息布局
dart
Row(
children: [
_buildStatCard('总选票', '$_totalVotes', Colors.blue),
const SizedBox(width: 12),
_buildStatCard('有效票', '${_totalVotes - _invalidVotes - _abstainedVotes}', Colors.green),
const SizedBox(width: 12),
_buildStatCard('废票', '$_invalidVotes', Colors.red),
const SizedBox(width: 12),
_buildStatCard('弃权', '$_abstainedVotes', Colors.grey),
],
)
颜色编码
- 蓝色:总选票
- 绿色:有效票
- 红色:废票
- 灰色:弃权票
7.3 操作按钮区域
dart
Row(
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: _submitVote,
icon: const Icon(Icons.how_to_vote),
label: const Text('确定投票'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 12),
backgroundColor: Colors.green,
),
),
),
const SizedBox(width: 12),
Expanded(
child: ElevatedButton.icon(
onPressed: _sortByVotes,
icon: const Icon(Icons.sort),
label: const Text('按票数排序'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 12),
),
),
),
],
)
八、完整代码实现
8.1 投票提交逻辑
dart
void _submitVote() {
// 情况1:弃权票
if (_selectedCandidates.isEmpty) {
setState(() {
_abstainedVotes++;
_totalVotes++;
_selectedCandidates.clear();
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('弃权票已记录')),
);
return;
}
// 情况2:废票(选择超过3人)
if (_selectedCandidates.length > 3) {
setState(() {
_invalidVotes++;
_totalVotes++;
_selectedCandidates.clear();
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('选择超过3人,该票作废'),
backgroundColor: Colors.red,
),
);
return;
}
// 情况3:有效票
setState(() {
for (var candidate in _candidates) {
if (_selectedCandidates.contains(candidate.name)) {
candidate.votes++;
}
}
_totalVotes++;
_selectedCandidates.clear();
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('投票成功')),
);
}
验证流程
- 检查是否为空(弃权)
- 检查是否超过3人(废票)
- 为选中的候选人增加票数
- 清空选择状态
8.2 排序功能
dart
void _sortByVotes() {
setState(() {
_candidates.sort((a, b) => b.votes.compareTo(a.votes));
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('已按票数排序')),
);
}
排序规则
- 按票数降序排列
- 票数相同时保持原有顺序
8.3 刷新重置功能
dart
void _refreshSystem() {
setState(() {
_candidates.clear();
_selectedCandidates.clear();
_candidatesController.clear();
_isVotingMode = false;
_resetStatistics();
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('系统已重置')),
);
}
void _resetStatistics() {
_totalVotes = 0;
_invalidVotes = 0;
_abstainedVotes = 0;
for (var candidate in _candidates) {
candidate.votes = 0;
}
}
九、运行效果与测试
9.1 项目运行命令
bash
cd E:\HarmonyOS\oh.code\voting_system
flutter run -d ohos
9.2 功能测试清单
候选人设置测试
- 输入单个候选人
- 输入多个候选人(逗号分隔)
- 输入多个候选人(空格分隔)
- 混合分隔符输入
- 空输入验证
- 取消按钮清空输入
投票功能测试
- 选中单个候选人
- 选中多个候选人(1-3人)
- 选中超过3人(废票)
- 不选中任何候选人(弃权)
统计功能测试
- 有效票正确统计
- 废票正确统计
- 弃权票正确统计
- 总票数正确计算
排序功能测试
- 按票数降序排列
- 排序后票数正确显示
重置功能测试
- 刷新后回到设置界面
- 所有数据清空
十、总结
本文详细介绍了使用Flutter for OpenHarmony开发投票管理系统的完整过程,涵盖了以下核心技术点:
- 复选框状态管理:CheckboxListTile + Set数据结构
- 选票验证逻辑:三层判断(弃权、废票、有效票)
- 实时统计机制:动态更新票数统计
- 排序算法:列表排序实现
- UI交互设计:直观的操作界面
这个项目展示了Flutter在交互式应用开发中的完整流程,代码结构清晰,功能完整。读者可以基于此项目添加更多功能,如:
- 候选人图片显示
- 投票时间限制
- 历史记录查看
- 导出投票结果
- 多轮投票支持
通过本文的学习,读者应该能够独立开发类似的交互式应用,掌握Flutter在鸿蒙平台上的状态管理和UI交互技巧。
欢迎加入开源鸿蒙跨平台社区 : 开源鸿蒙跨平台开发者社区
- 不选中任何候选人(弃权)
统计功能测试
- 有效票正确统计
- 废票正确统计
- 弃权票正确统计
- 总票数正确计算
排序功能测试
- 按票数降序排列
- 排序后票数正确显示
重置功能测试
- 刷新后回到设置界面
- 所有数据清空
十、总结
本文详细介绍了使用Flutter for OpenHarmony开发投票管理系统的完整过程,涵盖了以下核心技术点:
- 复选框状态管理:CheckboxListTile + Set数据结构
- 选票验证逻辑:三层判断(弃权、废票、有效票)
- 实时统计机制:动态更新票数统计
- 排序算法:列表排序实现
- UI交互设计:直观的操作界面
这个项目展示了Flutter在交互式应用开发中的完整流程,代码结构清晰,功能完整。读者可以基于此项目添加更多功能,如:
- 候选人图片显示
- 投票时间限制
- 历史记录查看
- 导出投票结果
- 多轮投票支持
通过本文的学习,读者应该能够独立开发类似的交互式应用,掌握Flutter在鸿蒙平台上的状态管理和UI交互技巧。
欢迎加入开源鸿蒙跨平台社区 : 开源鸿蒙跨平台开发者社区