Flutter 框架跨平台鸿蒙开发 - 思维录音机应用
文章摘要: 开源鸿蒙跨平台社区推出"思维录音机"应用,这是一款基于意识流写作理念的记录工具,采用Flutter框架开发(≥3.0.0),支持鸿蒙OS/Web平台。应用通过深紫色UI营造沉浸式思维空间,核心功能包括: 1️⃣ 录制控制(状态机+Timer实现开始/暂停/停止) 2️⃣ 思维分类(8种类型如灵感💡/疑问❓,各配主题色) 3️⃣ 数据可视化(时间轴图表分析思维模式)
欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
一、项目概述
运行效果图




1.1 应用简介
思维录音机是一款独特的意识流记录工具,灵感来源于"意识流写作"理念。应用模拟录音机的工作方式,真实记录你的每一个思维片段,不做任何编辑和修饰。就像录音机忠实地记录声音一样,思维录音机忠实地记录你的思维流动。
应用以深紫色为主色调,营造宁静、深邃的思维空间。涵盖录制控制、思维记录、回放浏览、统计分析四大模块,支持8种思维类型分类,通过时间轴和可视化图表帮助用户了解自己的思维模式。
1.2 核心功能
| 功能模块 | 功能描述 | 实现方式 |
|---|---|---|
| 录制控制 | 开始/暂停/停止录制 | 状态机 + Timer |
| 思维输入 | 记录思维内容 | TextField + 类型选择 |
| 实时显示 | 意识流实时展示 | ListView + 自动滚动 |
| 记录管理 | 浏览历史记录 | 列表展示 + 详情页 |
| 统计分析 | 思维数据分析 | 图表可视化 |
| 时间追踪 | 记录时间戳 | Duration计算 |
1.3 录制状态定义
| 序号 | 状态名称 | Emoji | 描述 |
|---|---|---|---|
| 1 | 空闲 | ⏸️ | 等待开始录制 |
| 2 | 录制中 | 🔴 | 正在记录思维 |
| 3 | 已暂停 | ⏯️ | 暂停录制状态 |
1.4 思维类型定义
| 序号 | 类型名称 | Emoji | 主题色 | 描述 |
|---|---|---|---|---|
| 1 | 灵感 | 💡 | #FFB74D | 突然的想法和创意 |
| 2 | 疑问 | ❓ | #64B5F6 | 需要思考的问题 |
| 3 | 情绪 | 💭 | #BA68C8 | 当下的情感状态 |
| 4 | 回忆 | 📷 | #4DB6AC | 过去的记忆片段 |
| 5 | 观察 | 👁️ | #81C784 | 对周围事物的感知 |
| 6 | 反思 | 🤔 | #F06292 | 对事物的思考 |
| 7 | 想象 | ✨ | #FFD54F | 天马行空的幻想 |
| 8 | 担忧 | 😰 | #E57373 | 焦虑和担心 |
1.5 技术栈
| 技术领域 | 技术选型 | 版本要求 |
|---|---|---|
| 开发框架 | Flutter | >= 3.0.0 |
| 编程语言 | Dart | >= 2.17.0 |
| 设计规范 | Material Design 3 | - |
| 动画控制 | AnimationController | - |
| 定时器 | Timer | - |
| 状态管理 | setState | - |
| 目标平台 | 鸿蒙OS / Web | API 21+ |
1.6 项目结构
lib/
└── main_thought_recorder.dart
├── ThoughtRecorderApp # 应用入口
├── RecordingState # 录制状态枚举
├── ThoughtType # 思维类型枚举
├── Thought # 思维数据模型
├── RecordingSession # 录制会话模型
├── ThoughtRecorderHomePage # 主页面(底部导航)
├── _buildRecordingPage # 录制页面
├── _buildSessionsPage # 记录列表页面
├── _buildStatsPage # 统计分析页面
├── SessionDetailPage # 会话详情页面
├── WavePainter # 波形绘制器
└── TimelineChartPainter # 时间轴图表绘制器
二、系统架构
2.1 整体架构图
2.2 类图设计
2.3 页面导航流程
2.4 录制流程
三、核心模块设计
3.1 数据模型设计
3.1.1 录制状态枚举 (RecordingState)
enum RecordingState {
idle('空闲', '点击开始录制你的思维'),
recording('录制中', '正在记录你的意识流...'),
paused('已暂停', '点击继续录制');
final String label;
final String description;
const RecordingState(this.label, this.description);
}
3.1.2 思维类型枚举 (ThoughtType)
enum ThoughtType {
idea('灵感', '💡', Color(0xFFFFB74D)),
question('疑问', '❓', Color(0xFF64B5F6)),
emotion('情绪', '💭', Color(0xFFBA68C8)),
memory('回忆', '📷', Color(0xFF4DB6AC)),
observation('观察', '👁️', Color(0xFF81C784)),
reflection('反思', '🤔', Color(0xFFF06292)),
dream('想象', '✨', Color(0xFFFFD54F)),
worry('担忧', '😰', Color(0xFFE57373));
final String label;
final String emoji;
final Color color;
const ThoughtType(this.label, this.emoji, this.color);
}
3.1.3 思维模型 (Thought)
class Thought {
final String id; // 唯一标识
final String content; // 思维内容
final ThoughtType type; // 思维类型
final DateTime timestamp; // 时间戳
final Duration relativeTime; // 相对时间
final String? note; // 备注
}
3.1.4 录制会话模型 (RecordingSession)
class RecordingSession {
final String id; // 唯一标识
final String title; // 会话标题
final DateTime startTime; // 开始时间
final DateTime? endTime; // 结束时间
final List<Thought> thoughts; // 思维列表
final Duration totalDuration; // 总时长
int get thoughtCount => thoughts.length;
}
3.1.5 思维类型分布
3.2 页面结构设计
3.2.1 主页面布局
3.2.2 录制页面结构
3.2.3 录制控制结构
3.2.4 会话详情页面结构
3.3 录制状态机
3.4 时间追踪流程
四、UI设计规范
4.1 配色方案
应用以深紫色为主色调,营造宁静、深邃的思维空间:
| 颜色类型 | 色值 | 用途 |
|---|---|---|
| 主色 | #5C6BC0 (Indigo 400) | 导航、强调元素 |
| 录制红 | #E53935 | 录制状态指示 |
| 灵感色 | #FFB74D | 灵感类型 |
| 疑问色 | #64B5F6 | 疑问类型 |
| 情绪色 | #BA68C8 | 情绪类型 |
| 回忆色 | #4DB6AC | 回忆类型 |
| 观察色 | #81C784 | 观察类型 |
| 反思色 | #F06292 | 反思类型 |
| 想象色 | #FFD54F | 想象类型 |
| 担忧色 | #E57373 | 担忧类型 |
4.2 状态配色
| 状态 | 色值 | 视觉效果 |
|---|---|---|
| 空闲 | 主色 | 平静蓝色 |
| 录制中 | 红色 | 脉冲动画 |
| 已暂停 | 橙色 | 静态显示 |
4.3 字体规范
| 元素 | 字号 | 字重 | 颜色 |
|---|---|---|---|
| 页面标题 | 24px | Bold | 主色 |
| 计时器 | 36px | Bold | 黑色 |
| 思维内容 | 14px | Regular | 黑色 |
| 类型标签 | 10px | Medium | 类型色 |
| 时间戳 | 10px | Regular | 灰色 |
4.4 组件规范
4.4.1 录制控制组件
┌─────────────────────────────────────┐
│ │
│ ┌─────────────┐ │
│ │ │ │
│ │ ● │ │
│ │ │ │
│ └─────────────┘ │
│ │
│ 05:32 │
│ 正在记录你的意识流... │
│ │
│ [暂停] │
│ │
└─────────────────────────────────────┘
● = 录制按钮(红色脉冲动画)
4.4.2 思维输入组件
┌─────────────────────────────────────────────┐
│ 记录思维 第 5 条 │
│ │
│ [💡灵感] [❓疑问] [💭情绪] [📷回忆] ... │
│ │
│ ┌─────────────────────────────────────────┐ │
│ │ 记录你此刻的思维... │ │
│ │ │ │
│ │ │ │
│ │ [➤] │ │
│ └─────────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
4.4.3 思维卡片
┌─────────────────────────────────────────────┐
│ ┌────┐ [💡灵感] 00:15 │
│ │ 💡 │ │
│ └────┘ 今天的天空特别蓝,突然想到了 │
│ 一个关于颜色的新想法 │
└─────────────────────────────────────────────┘
4.4.4 会话卡片
┌─────────────────────────────────────────────┐
│ ┌────┐ 思维记录 1 05:32 │
│ │ 🧠 │ 8条思维│
│ └────┘ 2天前 │
│ │
│ [💡3] [❓2] [💭2] [👁️1] │
└─────────────────────────────────────────────┘
4.4.5 统计卡片
┌─────────────────────────────────────────────┐
│ 概览 │
│ │
│ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ 📝 │ │ 🧠 │ │ ⏱️ │ │
│ │ 15 │ │ 87 │ │ 45分钟│ │
│ │记录次数│ │思维总数│ │ 总时长 │ │
│ └──────┘ └──────┘ └──────┘ │
└─────────────────────────────────────────────┘
五、核心功能实现
5.1 录制控制实现
void _startRecording() {
setState(() {
_recordingState = RecordingState.recording;
_recordingStartTime = DateTime.now();
_currentDuration = Duration.zero;
_currentThoughts.clear();
});
_durationTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
if (mounted) {
setState(() {
_currentDuration = DateTime.now().difference(_recordingStartTime!);
});
}
});
}
void _stopRecording() {
_durationTimer?.cancel();
if (_currentThoughts.isEmpty) {
setState(() {
_recordingState = RecordingState.idle;
});
return;
}
final session = RecordingSession(
id: DateTime.now().millisecondsSinceEpoch.toString(),
title: '思维记录 ${_sessions.length + 1}',
startTime: _recordingStartTime!,
endTime: DateTime.now(),
thoughts: List.from(_currentThoughts),
totalDuration: _currentDuration,
);
setState(() {
_sessions.insert(0, session);
_recordingState = RecordingState.idle;
_currentThoughts.clear();
});
}
5.2 思维添加实现
void _addThought() {
if (_thoughtController.text.trim().isEmpty) return;
final thought = Thought(
id: DateTime.now().millisecondsSinceEpoch.toString(),
content: _thoughtController.text.trim(),
type: _selectedType,
timestamp: DateTime.now(),
relativeTime: _currentDuration,
);
setState(() {
_currentThoughts.add(thought);
_thoughtController.clear();
});
// 自动滚动到底部
Future.delayed(const Duration(milliseconds: 100), () {
if (_scrollController.hasClients) {
_scrollController.animateTo(
_scrollController.position.maxScrollExtent,
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
);
}
});
}
5.3 脉冲动画实现
void initState() {
super.initState();
_pulseController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1500),
)..repeat(reverse: true);
}
Widget _buildRecordingControl() {
return AnimatedBuilder(
animation: _pulseController,
builder: (context, child) {
return Container(
width: 120 + (_recordingState == RecordingState.recording
? _pulseController.value * 10 : 0),
height: 120 + (_recordingState == RecordingState.recording
? _pulseController.value * 10 : 0),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _recordingState == RecordingState.recording
? Colors.red.withValues(alpha: 0.2 + _pulseController.value * 0.3)
: Theme.of(context).colorScheme.primaryContainer,
),
child: IconButton(
icon: Icon(_recordingState == RecordingState.recording
? Icons.stop
: Icons.fiber_manual_record),
onPressed: () {
if (_recordingState == RecordingState.idle) {
_startRecording();
} else if (_recordingState == RecordingState.recording) {
_stopRecording();
}
},
),
);
},
);
}
5.4 时间格式化
String _formatDuration(Duration duration) {
final hours = duration.inHours;
final minutes = duration.inMinutes.remainder(60);
final seconds = duration.inSeconds.remainder(60);
if (hours > 0) {
return '${hours.toString().padLeft(2, '0')}:'
'${minutes.toString().padLeft(2, '0')}:'
'${seconds.toString().padLeft(2, '0')}';
}
return '${minutes.toString().padLeft(2, '0')}:'
'${seconds.toString().padLeft(2, '0')}';
}
5.5 波形动画实现
class WavePainter extends CustomPainter {
final double animation;
final Color color;
WavePainter({required this.animation, required this.color});
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = color
..style = PaintingStyle.stroke
..strokeWidth = 2;
final path = Path();
final waveWidth = size.width / 4;
for (var i = 0; i < 4; i++) {
final x = i * waveWidth;
final y = size.height / 2 + sin((animation * 2 * pi) + i * pi / 2) * 20;
if (i == 0) {
path.moveTo(x, y);
} else {
path.lineTo(x, y);
}
}
canvas.drawPath(path, paint);
}
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
六、交互设计
6.1 录制流程
6.2 思维输入流程
6.3 会话浏览流程
七、扩展功能规划
7.1 后续版本规划
7.2 功能扩展建议
7.2.1 标签系统
增强分类功能:
- 自定义标签
- 标签筛选
- 标签统计
- 标签推荐
7.2.2 搜索功能
快速查找功能:
- 关键词搜索
- 类型筛选
- 时间范围
- 组合搜索
7.2.3 语音输入
便捷输入方式:
- 语音转文字
- 实时转录
- 多语言支持
- 离线识别
八、注意事项
8.1 开发注意事项
-
计时器管理:Timer需要在dispose时取消,避免内存泄漏
-
动画释放:AnimationController需要在dispose时释放
-
状态同步:录制状态变化时需要同步更新UI
-
自动滚动:添加思维后需要自动滚动到底部
-
数据持久化:会话数据需要本地存储
8.2 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 计时器不停止 | 未正确取消 | 在dispose中取消 |
| 动画卡顿 | Controller未释放 | 在dispose中释放 |
| 滚动失效 | Controller未初始化 | 检查ScrollController |
| 状态不同步 | 未调用setState | 确保状态更新 |
8.3 设计理念
🧠 思维录音机理念 🧠
思维如流水,转瞬即逝。
思维录音机,让思维有迹可循。
不做任何编辑,
不加任何修饰,
真实记录每一个念头。
就像录音机记录声音,
我们记录思维。
在意识流中,
发现真实的自己。
记录意识流,不做任何编辑
九、运行说明
9.1 环境要求
| 环境 | 版本要求 |
|---|---|
| Flutter SDK | >= 3.0.0 |
| Dart SDK | >= 2.17.0 |
| 鸿蒙OS | API 21+ |
9.2 运行命令
# 查看可用设备
flutter devices
# 运行到Web服务器
flutter run -d web-server -t lib/main_thought_recorder.dart --web-port 8121
# 运行到鸿蒙设备
flutter run -d 127.0.0.1:5555 lib/main_thought_recorder.dart
# 运行到Windows
flutter run -d windows -t lib/main_thought_recorder.dart
# 代码分析
flutter analyze lib/main_thought_recorder.dart
十、总结
思维录音机通过录制控制、思维记录、回放浏览、统计分析四大模块,为用户提供了一个独特的意识流记录平台。应用采用"不做编辑"的理念,真实记录每一个思维片段,帮助用户了解自己的思维模式。
核心功能涵盖录制控制、思维输入、实时展示、会话管理、统计分析五大模块。录制控制系统通过状态机和计时器实现精确控制;思维输入支持8种类型分类和实时添加;实时展示通过自动滚动保持最新思维可见;会话管理提供完整的记录浏览和详情查看;统计分析通过图表可视化展示思维分布和趋势。
应用采用Material Design 3设计规范,以深紫色为主色调,营造宁静、深邃的思维空间。通过本应用,希望能够帮助用户记录意识流,发现真实的自己。
记录你的意识流,不做任何编辑
更多推荐




所有评论(0)