1. 项目背景与设计理念
作为一个长期坚持写日记的人,我深知一个好的日记应用应该具备哪些特质。市面上的日记应用要么功能过于复杂,要么隐私保护不足,这促使我决定自己开发一个简单纯粹的日记功能。这个项目基于Flutter框架开发,目标是打造一个专注于记录本身、保护用户隐私的日记工具。
核心设计理念 可以概括为四个关键词:简单、情绪化、时间线、安全。简单是指界面和操作要足够简洁,减少用户的使用负担;情绪化是通过emoji表情快速标记心情状态;时间线则是按时间顺序组织日记,便于回顾;安全则是确保日记内容的私密性。
提示:在设计日记类应用时,切忌添加过多社交功能,这会让用户产生顾虑,无法真实记录内心想法。日记的本质是私人的自我对话空间。
2. 技术选型与架构设计
2.1 Flutter框架优势
选择Flutter作为开发框架主要基于以下几点考虑:
- 跨平台能力:一套代码可以同时运行在OpenHarmony和Android系统上,大大减少了开发维护成本
- 高性能渲染:Flutter的Skia引擎直接绘制UI,避免了原生平台的性能瓶颈
- 丰富的组件库:提供了大量现成的Material Design和Cupertino风格组件
- 热重载功能:开发时可以实时查看修改效果,极大提升开发效率
2.2 应用架构设计
采用典型的MVVM架构模式,分为三层:
- Model层:负责数据存储和加密,使用SharedPreferences进行本地存储
- ViewModel层:处理业务逻辑,包括日记的增删改查、加密解密等
- View层:UI展示,使用Flutter Widget构建界面
dart复制// 典型的三层架构示例
class DiaryModel {
Future<void> saveDiary(Diary diary) async {
// 数据加密和存储逻辑
}
}
class DiaryViewModel {
final DiaryModel _model;
Future<void> addDiary(Diary diary) async {
await _model.saveDiary(diary);
}
}
class DiaryPage extends StatelessWidget {
final DiaryViewModel _viewModel = DiaryViewModel();
// UI构建逻辑
}
3. 核心功能实现细节
3.1 日记列表展示
日记列表采用ListView.builder构建,这种懒加载方式对于可能包含大量日记条目的场景性能更优。每条日记以卡片形式展示,包含以下元素:
- 心情emoji:32sp大小,作为最显眼的视觉元素
- 日记标题:16sp,加粗显示
- 日期:12sp,灰色字体
- 内容预览:限制3行,超出部分显示省略号
dart复制ListView.builder(
itemCount: diaries.length,
itemBuilder: (context, index) {
return Card(
child: Padding(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(diaries[index].emoji, style: TextStyle(fontSize: 32)),
SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(diaries[index].title, style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
Text(formatDate(diaries[index].date), style: TextStyle(fontSize: 12, color: Colors.grey)),
],
),
),
],
),
SizedBox(height: 12),
Text(
diaries[index].content,
maxLines: 3,
overflow: TextOverflow.ellipsis,
style: TextStyle(height: 1.5),
),
],
),
),
);
},
)
3.2 心情选择器实现
心情选择器采用Wrap组件实现自动换行布局,提供8种常用emoji表情:
- 😊 开心
- 😄 大笑
- 😐 平静
- 😢 难过
- 😡 愤怒
- 😴 疲惫
- 🤔 思考
- 😎 酷
选中的表情会有视觉反馈:蓝色边框+浅蓝色背景。这种设计既保持了界面简洁,又提供了足够的情绪表达选择。
dart复制Wrap(
spacing: 12,
children: moods.map((mood) {
return GestureDetector(
onTap: () => setState(() => selectedMood = mood),
child: Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
color: selectedMood == mood ? Colors.blue.withOpacity(0.1) : null,
borderRadius: BorderRadius.circular(8),
border: selectedMood == mood ? Border.all(color: Colors.blue, width: 2) : null,
),
child: Text(mood, style: TextStyle(fontSize: 32)),
),
);
}).toList(),
)
3.3 数据存储与加密
日记数据使用SharedPreferences进行本地存储,所有数据在存储前都会进行加密处理。虽然示例中使用了Base64编码,但在实际项目中应该使用更安全的加密算法如AES。
加密存储流程:
- 将日记对象转换为JSON字符串
- 使用加密算法对字符串加密
- 将加密后的数据存入SharedPreferences
dart复制import 'package:encrypt/encrypt.dart';
final key = Key.fromUtf8('my32lengthsupersecretnooneknows1');
final iv = IV.fromLength(16);
final encrypter = Encrypter(AES(key));
String encrypt(String text) {
return encrypter.encrypt(text, iv: iv).base64;
}
String decrypt(String encrypted) {
return encrypter.decrypt64(encrypted, iv: iv);
}
4. 高级功能实现
4.1 日历视图集成
使用table_calendar插件实现日历功能,关键特性包括:
- 标记有日记的日期(显示小圆点)
- 点击日期跳转到对应日期的日记
- 支持月份切换和快速跳转
dart复制TableCalendar(
firstDay: DateTime(2020),
lastDay: DateTime(2030),
focusedDay: _focusedDay,
selectedDayPredicate: (day) => isSameDay(_selectedDay, day),
eventLoader: (day) => _getEventsForDay(day),
onDaySelected: (selectedDay, focusedDay) {
setState(() {
_selectedDay = selectedDay;
_focusedDay = focusedDay;
});
_loadDiariesForDay(selectedDay);
},
)
4.2 搜索与筛选功能
搜索功能支持标题和内容全文检索,筛选功能可以按心情状态过滤日记。实现要点:
- 使用小写转换确保搜索不区分大小写
- 对长内容使用contains方法进行子串匹配
- 为提升性能,对搜索结果进行缓存
dart复制List<Diary> searchDiaries(String query) {
if (query.isEmpty) return allDiaries;
final lowerQuery = query.toLowerCase();
return allDiaries.where((diary) {
return diary.title.toLowerCase().contains(lowerQuery) ||
diary.content.toLowerCase().contains(lowerQuery);
}).toList();
}
List<Diary> filterByMood(String mood) {
return allDiaries.where((diary) => diary.mood == mood).toList();
}
5. 隐私保护方案
5.1 本地存储加密
如前所述,所有日记数据在存储前都经过加密处理。加密密钥应当妥善保管,可以考虑以下方案:
- 使用用户设置的密码派生加密密钥
- 将密钥存储在安全存储区域(如Android的Keystore)
- 定期轮换加密密钥
5.2 应用访问控制
提供多层次的访问控制:
- 应用锁:密码或生物识别认证
- 日记隐藏:标记特定日记为隐藏,需要额外密码才能查看
- 虚假密码:输入特定密码进入"假模式",显示无关内容
dart复制Future<bool> authenticate() async {
final localAuth = LocalAuthentication();
try {
return await localAuth.authenticate(
localizedReason: '请验证身份以访问日记',
options: const AuthenticationOptions(biometricOnly: true),
);
} catch (e) {
return false;
}
}
6. 性能优化实践
6.1 列表性能优化
对于可能包含大量日记的列表,采取以下优化措施:
- 使用ListView.builder而非ListView
- 对日记卡片使用const构造函数
- 对复杂UI元素使用RepaintBoundary
- 分页加载日记数据
6.2 图片处理优化
虽然当前版本不支持图片,但为未来扩展考虑:
- 使用cached_network_image缓存网络图片
- 对本地图片进行适当压缩
- 懒加载图片,只在进入视图时加载
7. 实际使用体验与改进方向
经过几个月的实际使用,发现以下值得改进的地方:
- 图片支持:用户反馈希望能添加照片记录
- 天气集成:自动获取并记录当天天气
- 多设备同步:安全的端到端加密云同步
- Markdown支持:更丰富的内容格式选项
- 年度回顾:自动生成年度日记统计数据可视化
经验分享:开发日记类应用最重要的是保持核心功能的简洁稳定。添加新功能时要谨慎,确保不会影响应用的响应速度和隐私保护水平。我建议先做好基础功能,获得用户反馈后再逐步扩展。
8. 开发心得与建议
- 保持迭代节奏:初期版本功能要精简,快速上线获取用户反馈
- 重视测试:特别是加密和数据的部分,要确保万无一失
- 关注性能:日记应用应该即时响应,任何卡顿都会影响用户体验
- 设计一致性:保持UI风格统一,减少用户学习成本
- 备份机制:提供多种备份方案,避免用户数据丢失
在开发过程中,我发现Flutter的hot reload功能极大地提升了开发效率,特别是在调整UI细节时。同时,Dart语言的强类型特性也帮助避免了许多潜在的错误。