Flutter 框架跨平台鸿蒙开发 - 选择困难终结者应用
选择困难终结者应用摘要: 这是一款基于哲学理念设计的决策辅助应用,通过固定结果的随机算法帮助用户摆脱选择焦虑。应用采用Flutter开发,支持鸿蒙OS/Web平台,包含6大日常决策场景(如饮食、穿搭等)。核心功能是无论用户如何尝试,同一场景永远返回相同结果,以此传达"命运早已注定"的哲学思考。界面采用紫色主题和Material Design 3规范,包含决策引擎、历史记录和哲学
欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
一、项目概述
运行效果图






1.1 应用简介
选择困难终结者是一款充满哲学意味的决策辅助应用,它以一种独特的方式帮助用户摆脱选择困难的困扰。与传统的随机决定器不同,这款应用的核心设计理念是:命运早已注定,选择只是过程。
应用表面上看是在帮用户做决定,但实际上每次选择的结果都是相同的。这种看似"欺骗"的设计,实则蕴含着深刻的人生哲理——当我们意识到无论怎样选择,结果都早已注定时,选择本身的焦虑就会烟消云散。用户在反复尝试中逐渐领悟:真正重要的不是选择了什么,而是如何面对选择。
应用采用紫色为主色调,象征着神秘与智慧。界面设计简洁优雅,交互流畅自然。内置六大决策场景,涵盖日常生活的方方面面。每次决策后都会展示哲学启示,引导用户思考选择的本质。
1.2 核心功能
| 功能模块 | 功能描述 | 实现方式 |
|---|---|---|
| 决策引擎 | 永远返回相同结果 | 固定种子随机算法 |
| 场景选择 | 六大决策场景 | 网格布局卡片 |
| 结果展示 | 动画过渡+哲学提示 | 对话框+渐变卡片 |
| 历史记录 | 记录所有决策过程 | 时间线列表 |
| 哲学启示 | 人生哲理展示 | 卡片式布局 |
| 尝试计数 | 统计决策次数 | 状态变量计数 |
1.3 决策场景
| 序号 | 场景名称 | 图标 | 颜色 | 哲学提示 |
|---|---|---|---|---|
| 1 | 今天吃什么 | 🍽️ | #FF6B6B | 食物只是能量的载体,重要的是与谁共进餐 |
| 2 | 今天穿什么 | 👔 | #4ECDC4 | 外在只是表象,真正重要的是内心的光芒 |
| 3 | 周末做什么 | 🎯 | #FFE66D | 行动的意义在于过程,而非结果本身 |
| 4 | 去哪里玩 | 🗺️ | #95E1D3 | 目的地不重要,重要的是旅途中的心情 |
| 5 | 看什么电影 | 🎬 | #DDA0DD | 故事只是镜子,映照的是你内心的渴望 |
| 6 | 先做哪件事 | 📋 | #87CEEB | 顺序只是幻觉,每一刻都同样珍贵 |
1.4 技术栈
| 技术领域 | 技术选型 | 版本要求 |
|---|---|---|
| 开发框架 | Flutter | >= 3.0.0 |
| 编程语言 | Dart | >= 2.17.0 |
| 设计规范 | Material Design 3 | - |
| 状态管理 | setState | - |
| 动画系统 | AnimationController | - |
| 目标平台 | 鸿蒙OS / Web | API 21+ |
1.5 项目结构
lib/
└── main_decision_terminator.dart
├── DecisionTerminatorApp # 应用入口
├── DecisionScenario # 决策场景模型
├── DecisionRecord # 决策记录模型
├── DecisionTerminatorHomePage # 主页面(底部导航)
├── _buildDecisionPage # 决策页面
├── _buildHistoryPage # 历史页面
└── _buildInsightsPage # 启示页面
二、设计哲学
2.1 核心理念
2.2 命运的算法
应用的核心秘密在于使用固定种子的随机数生成器:
String _getAlwaysSameResult(DecisionScenario scenario) {
final seed = scenario.id.hashCode;
final random = Random(seed);
final index = random.nextInt(scenario.options.length);
return scenario.options[index];
}
这段代码看似随机,实则必然。每个场景的ID经过哈希运算后成为随机数生成器的种子,确保了无论何时何地,只要场景相同,结果就永远相同。这种设计巧妙地将"命运注定"的概念转化为代码实现。
2.3 哲学思考框架
三、系统架构
3.1 整体架构图
3.2 类图设计
3.3 决策流程时序图
四、核心功能实现
4.1 固定结果算法
这是整个应用的核心秘密所在:
String _getAlwaysSameResult(DecisionScenario scenario) {
final seed = scenario.id.hashCode;
final random = Random(seed);
final index = random.nextInt(scenario.options.length);
return scenario.options[index];
}
算法原理:
- 种子生成:将场景ID转换为哈希值作为随机种子
- 伪随机序列:使用固定种子初始化随机数生成器
- 结果确定:相同的种子永远产生相同的随机序列
这种设计的精妙之处在于:
- 表面上看起来是随机选择
- 实际上结果完全确定
- 用户无法察觉其中的规律
- 体现了"命运注定"的哲学思想
4.2 决策动画实现
Widget _buildDecidingAnimation() {
return AnimatedBuilder(
animation: _rotateAnimation,
builder: (context, child) {
final options = _selectedScenario!.options;
final currentIndex =
(_rotateAnimation.value * options.length * 5).floor() % options.length;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RotationTransition(
turns: _rotateAnimation,
child: Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: _selectedScenario!.color.withValues(alpha: 0.2),
shape: BoxShape.circle,
),
child: Text(
options[currentIndex],
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: _selectedScenario!.color,
),
),
),
),
const SizedBox(height: 16),
const CircularProgressIndicator(
color: Color(0xFF6A1B9A),
),
],
);
},
);
}
动画设计要点:
- 旋转效果:使用RotationTransition创造命运轮盘的感觉
- 快速切换:动画期间快速切换显示不同选项
- 视觉引导:通过颜色和形状引导用户注意力
- 心理预期:2秒的动画时长营造期待感
4.3 哲学对话框设计
void _showPhilosophicalDialog() {
showDialog(
context: context,
builder: (context) => AlertDialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
title: Row(
children: [
Text(_selectedScenario!.emoji, style: const TextStyle(fontSize: 28)),
const SizedBox(width: 12),
const Expanded(
child: Text('选择的智慧', style: TextStyle(fontSize: 20)),
),
],
),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
_selectedScenario!.color.withValues(alpha: 0.2),
_selectedScenario!.color.withValues(alpha: 0.1),
],
),
borderRadius: BorderRadius.circular(12),
),
child: Text(
_selectedScenario!.philosophicalHint,
style: const TextStyle(
fontSize: 16,
height: 1.6,
fontStyle: FontStyle.italic,
),
textAlign: TextAlign.center,
),
),
const SizedBox(height: 16),
Text(
'你已经尝试了 $_attemptCount 次',
style: TextStyle(fontSize: 14, color: Colors.grey.shade600),
),
const SizedBox(height: 8),
Text(
'结果始终如一',
style: TextStyle(
fontSize: 12,
color: Colors.grey.shade500,
fontStyle: FontStyle.italic,
),
),
],
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('我明白了'),
),
],
),
);
}
对话框设计理念:
- 渐进式揭示:先展示结果,再展示哲学提示
- 尝试计数:让用户意识到自己已经尝试多次
- 温和提示:用"结果始终如一"暗示真相
- 情感共鸣:通过哲学提示引发思考
4.4 场景选择器实现
Widget _buildScenarioSelector() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'选择你的困惑',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
mainAxisSpacing: 12,
crossAxisSpacing: 12,
childAspectRatio: 1.5,
),
itemCount: _scenarios.length,
itemBuilder: (context, index) {
final scenario = _scenarios[index];
final isSelected = _selectedScenario?.id == scenario.id;
return GestureDetector(
onTap: () {
setState(() {
_selectedScenario = scenario;
_selectedOption = null;
});
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
decoration: BoxDecoration(
gradient: isSelected
? LinearGradient(
colors: [
scenario.color.withValues(alpha: 0.3),
scenario.color.withValues(alpha: 0.1),
],
)
: null,
color: isSelected ? null : Colors.grey.shade50,
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: isSelected ? scenario.color : Colors.grey.shade200,
width: isSelected ? 2 : 1,
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(scenario.emoji, style: const TextStyle(fontSize: 32)),
const SizedBox(height: 8),
Text(
scenario.title,
style: TextStyle(
fontSize: 14,
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
color: isSelected ? scenario.color : Colors.black87,
),
),
],
),
),
);
},
),
],
);
}
五、UI设计规范
5.1 配色方案
应用采用紫色系为主色调,象征神秘、智慧与精神力量:
| 颜色类型 | 色值 | 用途 |
|---|---|---|
| 主色 | #6A1B9A (深紫) | 导航、按钮、强调元素 |
| 辅助色 | #9C27B0 (紫罗兰) | 渐变、次要元素 |
| 场景-吃 | #FF6B6B (珊瑚红) | 餐饮场景 |
| 场景-穿 | #4ECDC4 (青绿) | 服装场景 |
| 场景-做 | #FFE66D (明黄) | 活动场景 |
| 场景-去 | #95E1D3 (薄荷绿) | 地点场景 |
| 场景-看 | #DDA0DD (梅红) | 娱乐场景 |
| 场景-工作 | #87CEEB (天蓝) | 工作场景 |
5.2 字体规范
| 元素 | 字号 | 字重 | 颜色 |
|---|---|---|---|
| 应用标题 | 28px | Bold | #6A1B9A |
| 页面标题 | 24px | Bold | #FFFFFF |
| 场景名称 | 18px | Bold | #000000 |
| 结果文字 | 36px | Bold | #FFFFFF |
| 哲学提示 | 16px | Italic | #000000 |
| 辅助文字 | 12-14px | Regular | #757575 |
5.3 组件规范
5.3.1 场景卡片
┌─────────────────────┐
│ │
│ 🍽️ │
│ │
│ 今天吃什么 │
│ │
└─────────────────────┘
5.3.2 结果展示卡片
┌─────────────────────────────────────────────────┐
│ │
│ ✨ │
│ │
│ 命运的选择 │
│ │
│ 火锅 │
│ │
│ 已尝试 5 次 │
│ │
│ [🔄 再试一次] │
│ │
└─────────────────────────────────────────────────┘
5.3.3 哲学启示卡片
┌─────────────────────────────────────────────────┐
│ 💡 选择的本质 │
│ │
│ 我们花费大量时间纠结于选择, │
│ 却忘了选择本身并无绝对的对错。 │
│ 每一条路都有其独特的风景。 │
│ │
└─────────────────────────────────────────────────┘
六、交互设计
6.1 决策交互流程
6.2 用户心理变化曲线
6.3 页面切换状态
七、哲学内涵解析
7.1 存在主义视角
从存在主义的角度来看,选择困难终结者揭示了萨特所说的"存在先于本质"。我们常常认为每个选择都有其固有的正确答案,但实际上,选择本身并无绝对的对错。应用通过让每次结果都相同,暗示了这样一个观点:重要的不是选择了什么,而是如何承担选择的责任。
当我们意识到无论怎样选择,结果都早已注定时,我们反而能够从选择的焦虑中解脱出来。这种解脱不是消极的宿命论,而是一种积极的接受——接受生活的不确定性,接受自己的局限性,接受当下的美好。
7.2 斯多葛学派智慧
斯多葛学派强调区分"可控"与"不可控"的事物。选择困难终结者巧妙地将这种哲学思想融入应用设计中:
- 可控的:我们的态度、我们的行动、我们的接受
- 不可控的:命运的安排、结果的好坏、他人的看法
应用通过固定结果的设计,让用户在反复尝试中领悟:与其纠结于无法控制的结果,不如专注于可以控制的态度。这种领悟正是斯多葛学派所倡导的"宁静"(Ataraxia)。
7.3 佛教的无常观
佛教讲"诸行无常",一切都在变化之中。选择困难终结者虽然每次返回相同的结果,但这恰恰提醒我们:执着于结果本身就是一种痛苦。
当我们放下对结果的执着,专注于当下的体验,选择就不再是一种负担,而成为了一种探索。每一次"再试一次"都是一次新的体验,每一次"结果始终如一"都是一次觉醒的机会。
7.4 道家的无为思想
老子说:"无为而无不为。“选择困难终结者的设计理念与道家思想不谋而合。应用看似在帮用户做决定,实则是在引导用户"无为”——不是什么都不做,而是不强求、不执着、顺应自然。
当用户发现无论怎样选择,结果都相同时,他们可能会意识到:与其苦苦追求完美的选择,不如顺其自然,接受命运的安排。这种接受不是消极的放弃,而是积极的顺应,是与道合一的智慧。
八、扩展功能规划
8.1 后续版本规划
8.2 功能扩展建议
8.2.1 自定义场景
允许用户创建自己的决策场景:
- 添加场景名称和图标
- 设置选项列表
- 编写个性化的哲学提示
- 分享给其他用户
8.2.2 成就系统
通过成就系统引导用户深入思考:
- 觉醒者:尝试10次后发现结果相同
- 哲学家:阅读所有哲学提示
- 禅定者:连续7天使用应用
- 悟道者:分享自己的哲学感悟
8.2.3 社区哲学
建立哲学思考社区:
- 用户分享自己的感悟
- 点赞和评论功能
- 每日哲学名言
- 哲学家语录库
九、注意事项
9.1 开发注意事项
-
固定种子:确保每个场景使用固定的种子值
-
动画控制:AnimationController需要在dispose时释放
-
状态管理:使用setState管理本地状态
-
哲学提示:确保提示内容积极向上,避免消极暗示
9.2 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 结果不固定 | 种子值变化 | 检查hashCode是否一致 |
| 动画不播放 | 控制器未初始化 | 检查initState |
| 哲学提示不显示 | 场景未选择 | 检查_selectedScenario |
| 尝试计数错误 | 状态未更新 | 检查setState调用 |
9.3 使用提示
🎯 选择困难终结者使用小贴士 🎯
命运早已注定,选择只是过程。
不要纠结于结果,享受选择的过程。
当所有选择都指向同一个结果时,
那或许就是你内心真正的渴望。
记住:人生没有如果,只有结果。
十、运行说明
10.1 环境要求
| 环境 | 版本要求 |
|---|---|
| Flutter SDK | >= 3.0.0 |
| Dart SDK | >= 2.17.0 |
| 鸿蒙OS | API 21+ |
10.2 运行命令
# 查看可用设备
flutter devices
# 运行到Web服务器
flutter run -d web-server -t lib/main_decision_terminator.dart --web-port 8121
# 运行到鸿蒙设备
flutter run -d 127.0.0.1:5555 lib/main_decision_terminator.dart
# 运行到Windows
flutter run -d windows -t lib/main_decision_terminator.dart
# 代码分析
flutter analyze lib/main_decision_terminator.dart
十一、总结
选择困难终结者是一款充满哲学意味的应用,它以一种独特的方式帮助用户摆脱选择困难的困扰。应用的核心设计理念是"命运早已注定,选择只是过程",通过固定结果的算法,让用户在反复尝试中领悟选择的本质。
从技术实现来看,应用使用固定种子的随机数生成器确保每次结果相同,同时通过精美的动画和哲学提示营造沉浸式的用户体验。从哲学内涵来看,应用融合了存在主义、斯多葛学派、佛教和道家思想,引导用户思考选择的本质,接受命运安排,活在当下。
应用不仅是一个决策工具,更是一个哲学思考的载体。它提醒我们:重要的不是选择了什么,而是如何面对选择;重要的不是结果如何,而是过程中的成长。在这个充满选择的时代,选择困难终结者为我们提供了一种全新的视角——放下执念,接受当下,拥抱生活的每一个瞬间。
让选择成为智慧,让命运成为朋友
更多推荐


所有评论(0)