Flutter 框架跨平台鸿蒙开发 - 气味记忆唤醒应用
摘要: "气味记忆唤醒"是一款基于嗅觉记忆原理的创意应用,利用普鲁斯特效应(气味触发记忆)帮助用户关联气味与珍贵回忆。应用包含四大功能模块:记忆记录(建立气味-记忆关联)、气味识别(特征匹配)、记忆唤醒(通过气味触发回忆动画)、记忆档案(时光轴管理)。采用Flutter框架开发,支持鸿蒙OS/Web平台,界面以琥珀色为主色调,体现时光沉淀感。核心特色包括六类气味定义(自然、美食
欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
一、项目概述
运行效果图




1.1 应用简介
气味记忆唤醒是一款创意体验应用,通过建立气味与记忆的深度关联,让用户在"闻"到某种气味时,瞬间唤醒与之相关的珍贵回忆。普鲁斯特效应告诉我们,嗅觉记忆比视觉记忆更加持久深刻——某种气味能瞬间将我们带回童年的某个场景,重现当时的情感与画面。
应用以温暖的琥珀色为主色调,象征记忆的沉淀与时光的流转。涵盖记忆记录、气味识别、记忆唤醒、记忆档案四大模块。用户可以记录气味与记忆的关联,通过气味触发回忆,浏览记忆档案,重温那些转瞬即逝的美好时光。
1.2 核心功能
| 功能模块 | 功能描述 | 实现方式 |
|---|---|---|
| 记忆记录 | 记录气味与记忆关联 | 表单组件 |
| 气味识别 | 识别并匹配气味 | 特征匹配 |
| 记忆唤醒 | 通过气味唤醒记忆 | 动画展示 |
| 记忆档案 | 浏览管理记忆记录 | 列表展示 |
| 情感标签 | 标记记忆情感类型 | 多选标签 |
| 时光轴 | 按时间浏览记忆 | 时间线展示 |
1.3 气味类型定义
| 序号 | 类型名称 | Emoji | 描述 |
|---|---|---|---|
| 1 | 自然气息 | 🌿 | 花草树木、泥土雨露 |
| 2 | 美食记忆 | 🍳 | 家常菜、烘焙、饮品 |
| 3 | 时光印记 | 📚 | 旧书、老物件、岁月 |
| 4 | 人物气息 | 👤 | 亲人朋友、熟悉的人 |
| 5 | 场所氛围 | 🏠 | 家、学校、特定地点 |
| 6 | 季节流转 | 🌸 | 春夏秋冬的独特气息 |
1.4 记忆强度定义
| 序号 | 强度名称 | Emoji | 数值 | 描述 |
|---|---|---|---|---|
| 1 | 淡淡的 | 🌫️ | 0.3 | 若隐若现的记忆 |
| 2 | 清晰的 | 🌅 | 0.6 | 记忆画面清晰 |
| 3 | 深刻的 | 🌟 | 0.8 | 印象深刻难忘 |
| 4 | 永恒的 | 💎 | 1.0 | 刻骨铭心的记忆 |
1.5 情感类型定义
| 序号 | 情感名称 | Emoji | 颜色 | 描述 |
|---|---|---|---|---|
| 1 | 温馨 | 🥰 | #FFB74D | 温暖幸福的记忆 |
| 2 | 怀念 | 🥺 | #B39DDB | 怀旧感伤的记忆 |
| 3 | 愉悦 | 😊 | #81C784 | 开心快乐的记忆 |
| 4 | 感动 | 🥹 | #4FC3F7 | 触动心弦的记忆 |
| 5 | 平静 | 😌 | #90CAF9 | 宁静安详的记忆 |
| 6 | 遗憾 | 😢 | #CE93D8 | 略带遗憾的记忆 |
1.6 唤醒方式定义
| 序号 | 唤醒方式 | Emoji | 描述 |
|---|---|---|---|
| 1 | 气味匹配 | 🔍 | 识别相似气味触发 |
| 2 | 主动回忆 | 💭 | 主动选择气味回忆 |
| 3 | 随机唤醒 | 🎲 | 随机触发记忆唤醒 |
| 4 | 时间提醒 | ⏰ | 特定时间自动唤醒 |
1.7 技术栈
| 技术领域 | 技术选型 | 版本要求 |
|---|---|---|
| 开发框架 | Flutter | >= 3.0.0 |
| 编程语言 | Dart | >= 2.17.0 |
| 设计规范 | Material Design 3 | - |
| 动画效果 | AnimationController | - |
| 自定义绘制 | CustomPainter | - |
| 状态管理 | StatefulWidget | - |
| 目标平台 | 鸿蒙OS / Web | API 21+ |
1.8 项目结构
lib/
└── main_scent_memory_awakening.dart
├── ScentMemoryAwakeningApp # 应用入口
├── ScentType # 气味类型枚举
├── MemoryIntensity # 记忆强度枚举
├── EmotionType # 情感类型枚举
├── AwakeningMethod # 唤醒方式枚举
├── ScentMemory # 气味记忆模型
├── MemoryAwakening # 记忆唤醒模型
├── ScentMemoryHomePage # 主页面(底部导航)
├── _buildRecordPage # 记录页面
├── _buildAwakeningPage # 唤醒页面
├── _buildArchivePage # 档案页面
├── _buildProfilePage # 关于页面
├── MemoryAwakeningPainter # 唤醒效果绘制器
└── ScentWavePainter # 气味波动绘制器
二、系统架构
2.1 整体架构图
2.2 类图设计
2.3 页面导航流程
2.4 记忆唤醒流程
三、核心模块设计
3.1 数据模型设计
3.1.1 气味类型枚举 (ScentType)
enum ScentType {
nature(label: '自然气息', emoji: '🌿', description: '花草树木、泥土雨露'),
food(label: '美食记忆', emoji: '🍳', description: '家常菜、烘焙、饮品'),
memory(label: '时光印记', emoji: '📚', description: '旧书、老物件、岁月'),
person(label: '人物气息', emoji: '👤', description: '亲人朋友、熟悉的人'),
place(label: '场所氛围', emoji: '🏠', description: '家、学校、特定地点'),
season(label: '季节流转', emoji: '🌸', description: '春夏秋冬的独特气息');
final String label;
final String emoji;
final String description;
}
3.1.2 记忆强度枚举 (MemoryIntensity)
enum MemoryIntensity {
faint(label: '淡淡的', emoji: '🌫️', value: 0.3),
clear(label: '清晰的', emoji: '🌅', value: 0.6),
deep(label: '深刻的', emoji: '🌟', value: 0.8),
eternal(label: '永恒的', emoji: '💎', value: 1.0);
final String label;
final String emoji;
final double value;
}
3.1.3 气味记忆模型 (ScentMemory)
class ScentMemory {
final String id; // 记忆ID
final String scentName; // 气味名称
final ScentType scentType; // 气味类型
final String memoryTitle; // 记忆标题
final String memoryContent; // 记忆内容
final List<EmotionType> emotions; // 情感标签
final MemoryIntensity intensity; // 记忆强度
final DateTime memoryTime; // 记忆发生时间
final String location; // 记忆地点
final List<String> tags; // 标签
final DateTime createdAt; // 创建时间
final int awakenCount; // 唤醒次数
}
3.1.4 记忆唤醒模型 (MemoryAwakening)
class MemoryAwakening {
final String id; // 唤醒ID
final ScentMemory memory; // 关联记忆
final AwakeningMethod method; // 唤醒方式
final DateTime awakenedAt; // 唤醒时间
final double matchScore; // 匹配分数
final String notes; // 唤醒备注
}
3.1.5 情感类型分布
3.2 页面结构设计
3.2.1 主页面布局
3.2.2 记录页结构
3.2.3 唤醒页结构
3.2.4 档案页结构
3.3 气味识别逻辑
3.4 记忆唤醒动画逻辑
四、UI设计规范
4.1 配色方案
应用以温暖的琥珀色为主色调,象征记忆的沉淀与时光的流转:
| 颜色类型 | 色值 | 用途 |
|---|---|---|
| 主色 | #FFB74D (Amber) | 导航、主题元素 |
| 辅助色 | #FFA726 | 唤醒页面 |
| 第三色 | #FF9800 | 档案页面 |
| 强调色 | #FFC107 | 记录页面 |
| 背景色 | #FFFBF5 | 页面背景 |
| 卡片背景 | #FFFFFF | 记忆卡片 |
4.2 情感色彩映射
| 情感 | 色值 | 视觉效果 |
|---|---|---|
| 温馨 | #FFB74D | 温暖金色 |
| 怀念 | #B39DDB | 柔和紫色 |
| 愉悦 | #81C784 | 清新绿色 |
| 感动 | #4FC3F7 | 明亮蓝色 |
| 平静 | #90CAF9 | 淡雅蓝色 |
| 遗憾 | #CE93D8 | 淡紫色 |
4.3 字体规范
| 元素 | 字号 | 字重 | 颜色 |
|---|---|---|---|
| 页面标题 | 24px | Bold | 主色 |
| 记忆标题 | 18px | Bold | #000000 |
| 气味名称 | 16px | Medium | 主色 |
| 记忆内容 | 14px | Regular | #424242 |
| 情感标签 | 12px | Regular | 对应颜色 |
4.4 组件规范
4.4.1 气味选择卡片
┌─────────────────────────────────────┐
│ 选择气味类型 │
│ │
│ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ 🌿 │ │ 🍳 │ │ 📚 │ │
│ │自然 │ │美食 │ │时光 │ │
│ │气息 │ │记忆 │ │印记 │ │
│ └──────┘ └──────┘ └──────┘ │
│ │
│ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ 👤 │ │ 🏠 │ │ 🌸 │ │
│ │人物 │ │场所 │ │季节 │ │
│ │气息 │ │氛围 │ │流转 │ │
│ └──────┘ └──────┘ └──────┘ │
└─────────────────────────────────────┘
4.4.2 情感标签选择
┌─────────────────────────────────────┐
│ 选择情感标签 │
│ │
│ [🥰 温馨] [🥺 怀念] [😊 愉悦] │
│ [🥹 感动] [😌 平静] [😢 遗憾] │
└─────────────────────────────────────┘
4.4.3 记忆强度滑块
┌─────────────────────────────────────┐
│ 记忆强度 │
│ │
│ 🌫️ 淡淡的 ──────●──────── 🌟 深刻 │
│ │
│ 当前强度: 清晰的 🌅 │
└─────────────────────────────────────┘
4.4.4 唤醒动画区域
┌─────────────────────────────────────┐
│ ┌─────────────────────────────┐ │
│ │ │ │
│ │ ~~~~~~~~ │ │
│ │ ~~气味波动~~~ │ │
│ │ ~~~~~~~~ │ │
│ │ │ │
│ │ 🌿 雨后泥土 │ │
│ │ │ │
│ └─────────────────────────────┘ │
│ │
│ [🔍 识别气味] │
└─────────────────────────────────────┘
4.4.5 记忆卡片展示
┌─────────────────────────────────────┐
│ 🌿 雨后泥土 │
│ ───────────────────────────────── │
│ 📝 童年的雨天 │
│ │
│ 记得小时候每到下雨天,就会闻到 │
│ 泥土特有的清香。那是一种混合着... │
│ │
│ ───────────────────────────────── │
│ 🥰 温馨 🥺 怀念 │
│ 🌅 清晰的记忆 │
│ 📍 外婆家的院子 │
│ 📅 1998年夏天 │
│ │
│ 🔔 已唤醒 5 次 │
└─────────────────────────────────────┘
五、核心功能实现
5.1 气味波动绘制实现
class ScentWavePainter extends CustomPainter {
final double progress;
final ScentType scentType;
final List<EmotionType> emotions;
void paint(Canvas canvas, Size size) {
final center = Offset(size.width / 2, size.height / 2);
for (int i = 0; i < 5; i++) {
final waveProgress = (progress + i * 0.2) % 1.0;
final radius = size.width * 0.3 * waveProgress;
final alpha = (1.0 - waveProgress) * 0.5;
final emotionColor = emotions.isNotEmpty
? emotions[0].color
: const Color(0xFFFFB74D);
final wavePaint = Paint()
..color = emotionColor.withValues(alpha: alpha)
..style = PaintingStyle.stroke
..strokeWidth = 3.0;
canvas.drawCircle(center, radius, wavePaint);
}
_drawScentIcon(canvas, size, center);
}
void _drawScentIcon(Canvas canvas, Size size, Offset center) {
final textPainter = TextPainter(
text: TextSpan(
text: scentType.emoji,
style: const TextStyle(fontSize: 48),
),
textDirection: TextDirection.ltr,
);
textPainter.layout();
textPainter.paint(
canvas,
Offset(
center.dx - textPainter.width / 2,
center.dy - textPainter.height / 2,
),
);
}
}
5.2 记忆唤醒动画实现
class MemoryAwakeningPainter extends CustomPainter {
final double animationProgress;
final ScentMemory memory;
void paint(Canvas canvas, Size size) {
if (animationProgress < 0.3) {
_drawWavePhase(canvas, size);
} else if (animationProgress < 0.6) {
_drawMemoryEmerging(canvas, size);
} else if (animationProgress < 0.9) {
_drawEmotionRendering(canvas, size);
} else {
_drawCompleteMemory(canvas, size);
}
}
void _drawWavePhase(Canvas canvas, Size size) {
final waveProgress = animationProgress / 0.3;
for (int i = 0; i < 3; i++) {
final radius = size.width * 0.4 * (waveProgress + i * 0.15);
final alpha = (1.0 - waveProgress) * 0.3;
final paint = Paint()
..color = _getEmotionColor().withValues(alpha: alpha)
..style = PaintingStyle.stroke
..strokeWidth = 2.0;
canvas.drawCircle(
Offset(size.width / 2, size.height / 2),
radius,
paint,
);
}
}
void _drawMemoryEmerging(Canvas canvas, Size size) {
final emergeProgress = (animationProgress - 0.3) / 0.3;
final alpha = emergeProgress;
final bgPaint = Paint()
..color = Colors.white.withValues(alpha: alpha * 0.9);
canvas.drawRect(
Rect.fromLTWH(0, 0, size.width, size.height),
bgPaint,
);
final titlePainter = TextPainter(
text: TextSpan(
text: memory.memoryTitle,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.black.withValues(alpha: alpha),
),
),
textDirection: TextDirection.ltr,
);
titlePainter.layout();
titlePainter.paint(
canvas,
Offset(
(size.width - titlePainter.width) / 2,
size.height * 0.3,
),
);
}
Color _getEmotionColor() {
if (memory.emotions.isNotEmpty) {
return memory.emotions.first.color;
}
return const Color(0xFFFFB74D);
}
}
5.3 气味识别匹配实现
class ScentRecognizer {
final List<ScentMemory> memoryDatabase;
ScentMemory? recognizeScent(String scentName, ScentType type) {
final candidates = <ScentMemory>[];
for (final memory in memoryDatabase) {
final score = _calculateMatchScore(scentName, type, memory);
if (score > 0.6) {
candidates.add(memory);
}
}
if (candidates.isEmpty) return null;
candidates.sort((a, b) =>
_calculateMatchScore(scentName, type, b)
.compareTo(_calculateMatchScore(scentName, type, a))
);
return candidates.first;
}
double _calculateMatchScore(
String inputName,
ScentType inputType,
ScentMemory memory
) {
double score = 0.0;
if (memory.scentType == inputType) {
score += 0.4;
}
final nameSimilarity = _calculateStringSimilarity(
inputName.toLowerCase(),
memory.scentName.toLowerCase(),
);
score += nameSimilarity * 0.6;
return score;
}
double _calculateStringSimilarity(String s1, String s2) {
if (s1 == s2) return 1.0;
if (s1.contains(s2) || s2.contains(s1)) return 0.8;
final commonChars = s1.split('').where((c) => s2.contains(c)).length;
return commonChars / ((s1.length + s2.length) / 2);
}
}
5.4 记忆保存实现
void _saveMemory() {
if (_scentNameController.text.isEmpty ||
_memoryTitleController.text.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('请填写气味名称和记忆标题')),
);
return;
}
final memory = ScentMemory(
id: 'memory_${DateTime.now().millisecondsSinceEpoch}',
scentName: _scentNameController.text,
scentType: _selectedScentType,
memoryTitle: _memoryTitleController.text,
memoryContent: _memoryContentController.text,
emotions: _selectedEmotions,
intensity: _selectedIntensity,
memoryTime: _selectedTime,
location: _locationController.text,
tags: _tags,
createdAt: DateTime.now(),
awakenCount: 0,
);
setState(() {
_memories.insert(0, memory);
_scentNameController.clear();
_memoryTitleController.clear();
_memoryContentController.clear();
_locationController.clear();
_selectedEmotions.clear();
_tags.clear();
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('记忆已保存')),
);
}
5.5 唤醒记录实现
void _recordAwakening(ScentMemory memory, AwakeningMethod method) {
final awakening = MemoryAwakening(
id: 'awakening_${DateTime.now().millisecondsSinceEpoch}',
memory: memory,
method: method,
awakenedAt: DateTime.now(),
matchScore: 1.0,
);
setState(() {
final index = _memories.indexWhere((m) => m.id == memory.id);
if (index != -1) {
final updatedMemory = ScentMemory(
id: memory.id,
scentName: memory.scentName,
scentType: memory.scentType,
memoryTitle: memory.memoryTitle,
memoryContent: memory.memoryContent,
emotions: memory.emotions,
intensity: memory.intensity,
memoryTime: memory.memoryTime,
location: memory.location,
tags: memory.tags,
createdAt: memory.createdAt,
awakenCount: memory.awakenCount + 1,
);
_memories[index] = updatedMemory;
}
_awakenings.insert(0, awakening);
});
}
六、交互设计
6.1 记忆记录流程
6.2 记忆唤醒流程
6.3 档案浏览流程
七、扩展功能规划
7.1 后续版本规划
7.2 功能扩展建议
7.2.1 AI气味识别
识别功能:
- 基于描述的智能识别
- 气味特征学习
- 记忆关联推荐
- 情感分析
7.2.2 记忆分享
分享功能:
- 生成记忆卡片图片
- 分享到社交平台
- 记忆故事导出
- 匿名分享社区
7.2.3 智能提醒
提醒功能:
- 特定时间自动唤醒
- 天气关联提醒
- 地点触发唤醒
- 周年纪念提醒
八、注意事项
8.1 开发注意事项
-
动画性能:唤醒动画需优化渲染性能,避免卡顿
-
数据持久化:记忆数据需本地持久化存储
-
隐私保护:记忆内容涉及隐私,需做好数据保护
-
匹配算法:气味匹配算法需持续优化,提高准确率
-
用户体验:唤醒过程需流畅自然,增强沉浸感
8.2 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 唤醒动画卡顿 | 渲染负担过重 | 分阶段渲染优化 |
| 匹配准确率低 | 特征提取不足 | 优化匹配算法 |
| 记忆丢失 | 数据未持久化 | 添加本地存储 |
| 情感色彩异常 | 颜色映射错误 | 检查颜色配置 |
| 动画进度异常 | 状态更新不及时 | 优化状态管理 |
8.3 使用技巧
🌸 气味记忆唤醒使用技巧 🌸
记忆记录技巧
- 详细描述气味特征,提高识别准确率
- 记录具体的时间地点,增强记忆真实感
- 选择合适的情感标签,便于情感渲染
- 适当添加标签,方便后续搜索
唤醒体验优化
- 在安静环境中体验唤醒,增强沉浸感
- 仔细回忆气味细节,提高匹配成功率
- 记录唤醒感受,丰富记忆层次
- 定期浏览档案,强化记忆关联
档案管理建议
- 定期整理记忆档案,删除重复记录
- 使用筛选功能快速查找记忆
- 关注唤醒次数,发现重要记忆
- 及时更新记忆内容,保持准确性
九、运行说明
9.1 环境要求
| 环境 | 版本要求 |
|---|---|
| Flutter SDK | >= 3.0.0 |
| Dart SDK | >= 2.17.0 |
| 鸿蒙OS | API 21+ |
| Web浏览器 | Chrome 90+ |
9.2 运行命令
# 查看可用设备
flutter devices
# 运行到Web服务器
flutter run -d web-server -t lib/main_scent_memory_awakening.dart --web-port 8140
# 运行到鸿蒙设备
flutter run -d 127.0.0.1:5555 lib/main_scent_memory_awakening.dart
# 代码分析
flutter analyze lib/main_scent_memory_awakening.dart
十、总结
气味记忆唤醒应用通过记忆记录、气味识别、记忆唤醒、记忆档案四大模块,为用户提供了一个独特的嗅觉记忆管理平台。应用支持6种气味类型、4种记忆强度、6种情感类型、4种唤醒方式,让用户在气味的世界中重温珍贵回忆。
核心功能涵盖气味记忆记录、智能识别匹配、沉浸式唤醒体验、档案管理浏览四大模块。气味类型从自然气息到季节流转,覆盖生活中常见的气味场景;记忆强度从淡淡的到永恒的,记录不同深度的记忆印象;情感类型从温馨到遗憾,标记记忆的情感色彩;唤醒方式从气味匹配到时间提醒,提供多样化的记忆触发方式。
应用采用 Material Design 3 设计规范,以温暖的琥珀色为主色调,象征记忆的沉淀与时光的流转。通过本应用,希望能够帮助用户建立气味与记忆的深度关联,让那些转瞬即逝的嗅觉体验成为永恒的记忆财富,在气味的世界中重温美好时光。
气味记忆唤醒——让记忆有味道
更多推荐

所有评论(0)