Flutter 投票系统:数据统计与排序算法深度解析
Flutter 投票系统涉及数据统计与排序算法的核心实现。内容包括选票验证逻辑(弃权、废票、有效票)、实时统计机制更新策略、Dart 内置及自定义排序规则、状态管理最佳实践、数据可视化展示以及性能优化方案。重点讲解了 setState 批量更新、列表懒加载、多条件排序等关键技术点,帮助开发者构建高效准确的统计系统。

Flutter 投票系统涉及数据统计与排序算法的核心实现。内容包括选票验证逻辑(弃权、废票、有效票)、实时统计机制更新策略、Dart 内置及自定义排序规则、状态管理最佳实践、数据可视化展示以及性能优化方案。重点讲解了 setState 批量更新、列表懒加载、多条件排序等关键技术点,帮助开发者构建高效准确的统计系统。

投票系统涉及以下核心算法:

| 规则 | 条件 | 结果 |
|---|---|---|
| 弃权票 | 选中 0 人 | 弃权计数 +1 |
| 有效票 | 选中 1-3 人 | 各候选人票数 +1 |
| 废票 | 选中>3 人 | 废票计数 +1 |
void _submitVote() {
// 第一层判断:弃权检测
if (_selectedCandidates.isEmpty) {
_handleAbstainedVote();
return;
}
// 第二层判断:废票检测
if (_selectedCandidates.length > 3) {
_handleInvalidVote();
return;
}
// 第三层:有效票处理
_handleValidVote();
}

void _handleAbstainedVote() {
setState(() {
_abstainedVotes++;
_totalVotes++;
_selectedCandidates.clear();
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('弃权票已记录')),
);
}
处理要点
void _handleInvalidVote() {
setState(() {
_invalidVotes++;
_totalVotes++;
_selectedCandidates.clear();
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('选择超过 3 人,该票作废'),
backgroundColor: Colors.red,
),
);
}
处理要点
void _handleValidVote() {
setState(() {
for (var candidate in _candidates) {
if (_selectedCandidates.contains(candidate.name)) {
candidate.votes++;
}
}
_totalVotes++;
_selectedCandidates.clear();
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('投票成功')),
);
}
处理要点
class _VotingSystemPageState extends State<VotingSystemPage> {
int _totalVotes = 0;
int _invalidVotes = 0;
int _abstainedVotes = 0;
}
// 每次投票后更新
setState(() {
_totalVotes++;
});
int get _validVotes {
return _totalVotes - _invalidVotes - _abstainedVotes;
}
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)),
],
),
),
),
);
}
// 方式一:实时计算
_buildStatCard('有效票', '${_totalVotes - _invalidVotes - _abstainedVotes}', Colors.green)
// 方式二:使用 getter
int get _validVotes => _totalVotes - _invalidVotes - _abstainedVotes;
// 方式三:单独存储
int _validVotes = 0;
setState(() {
_validVotes++;
});
推荐方式

按候选人得票数从高到低排序,方便查看排名。
void _sortByVotes() {
setState(() {
_candidates.sort((a, b) => b.votes.compareTo(a.votes));
});
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('已按票数排序')));
}
排序原理
_candidates.sort((a, b) => b.votes.compareTo(a.votes));
_candidates.sort((a, b) => a.votes.compareTo(b.votes));
_candidates.sort((a, b) => a.name.compareTo(b.name));
_candidates.sort((a, b) {
int voteCompare = b.votes.compareTo(a.votes);
if (voteCompare != 0) {
return voteCompare;
}
return a.name.compareTo(b.name);
});
Dart 的 sort 是稳定排序,相同元素的相对顺序保持不变。
Dart 使用的是混合排序算法:
对于小型投票系统(<100 候选人),性能完全足够。
使用 StatefulWidget + setState:
class _VotingSystemPageState extends State<VotingSystemPage> {
final List<Candidate> _candidates = [];
final Set<String> _selectedCandidates = {};
int _totalVotes = 0;
void _updateState() {
setState(() {
// 修改状态
});
}
}
// 不推荐:多次 setState
setState(() { _totalVotes++; });
setState(() { _selectedCandidates.clear(); });
// 推荐:单次 setState
setState(() {
_totalVotes++;
_selectedCandidates.clear();
});
void _toggleSelection(String name) {
bool wasSelected = _selectedCandidates.contains(name);
bool willBeSelected = !wasSelected;
setState(() {
if (willBeSelected) {
_selectedCandidates.add(name);
} else {
_selectedCandidates.remove(name);
}
});
}
保存当前状态以便恢复:
Map<String, dynamic> _getStateSnapshot() {
return {
'candidates': _candidates.map((c) => {'name': c.name, 'votes': c.votes}).toList(),
'totalVotes': _totalVotes,
'invalidVotes': _invalidVotes,
'abstainedVotes': _abstainedVotes,
};
}
使用颜色区分不同类型的票:
_buildStatCard('总选票', '$_totalVotes', Colors.blue);
_buildStatCard('有效票', '$_validVotes', Colors.green);
_buildStatCard('废票', '$_invalidVotes', Colors.red);
_buildStatCard('弃权', '$_abstainedVotes', Colors.grey);
使用进度条显示得票比例:
Widget _buildProgressBar(Candidate candidate, int totalVotes) {
if (totalVotes == 0) return const SizedBox.shrink();
double percentage = candidate.votes / totalVotes;
return Column(
children: [
Text('${candidate.name}: ${candidate.votes}票'),
LinearProgressIndicator(
value: percentage,
backgroundColor: Colors.grey[200],
valueColor: AlwaysStoppedAnimation<Color>(Colors.blue),
),
Text('${(percentage * 100).toStringAsFixed(1)}%'),
],
);
}
为前三名添加特殊标识:
Widget _buildRankBadge(int index) {
if (index == 0) return const Icon(Icons.emoji_events, color: Colors.amber);
if (index == 1) return const Icon(Icons.emoji_events, color: Colors.grey);
if (index == 2) return const Icon(Icons.emoji_events, color: Colors.brown);
return null;
}
class VoteRecord {
final DateTime timestamp;
final List<String> selectedCandidates;
final VoteType type;
enum VoteType { valid, invalid, abstained }
}
Future<void> _exportResults() async {
final buffer = StringBuffer();
buffer.writeln('排名,候选人,得票数,得票率');
final sortedCandidates = List.from(_candidates);
sortedCandidates.sort((a, b) => b.votes.compareTo(a.votes));
for (int i = 0; i < sortedCandidates.length; i++) {
final candidate = sortedCandidates[i];
final percentage = _totalVotes > 0 ? (candidate.votes / _totalVotes * 100).toStringAsFixed(2) : '0.00';
buffer.writeln('${i + 1},${candidate.name},${candidate.votes},$percentage%');
}
}
void _startNewRound() {
_roundResults.add({
'round': _currentRound,
'candidates': List.from(_candidates),
'statistics': {
'total': _totalVotes,
'invalid': _invalidVotes,
'abstained': _abstainedVotes,
},
});
setState(() {
_currentRound++;
_resetStatistics();
for (var candidate in _candidates) {
candidate.votes = 0;
}
});
}
使用 const 构造函数:
const Card(child: Text('投票规则'));
对于大量候选人,使用 ListView.builder:
ListView.builder(
itemCount: _candidates.length,
itemBuilder: (context, index) => _buildCandidateItem(_candidates[index]),
);
只在必要时更新状态:
void _toggleSelection(String name) {
bool alreadySelected = _selectedCandidates.contains(name);
if (alreadySelected && _selectedCandidates.length > 3) return;
setState(() {
if (alreadySelected) {
_selectedCandidates.remove(name);
} else {
_selectedCandidates.add(name);
}
});
}
本文深入讲解了投票管理系统中的统计和排序技术,主要内容包括:
掌握这些技术可以让你开发出功能强大、性能优秀的投票应用。在实际项目中,还需要考虑数据安全、防作弊、并发访问等方面,确保应用的公正性和可靠性。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online