写日记这个习惯,我自己坚持了好几年。从最开始的纸质日记本,到后来的电子日记,再到现在自己开发的这个日记功能,记录生活的方式一直在变,但记录的意义从未改变
在这里插入图片描述

为什么要做日记功能

你可能会想,现在社交媒体这么发达,发个朋友圈、微博不就行了吗?但说实话,真正的日记是写给自己看的,不需要考虑别人的眼光,可以完全真实地记录自己的想法和感受。

我在设计这个日记功能的时候,有几个核心想法:

  • 简单纯粹:不要太多花里胡哨的功能,专注于记录本身
  • 情绪标记:用emoji表情快速标记当天的心情
  • 时间轴展示:按时间顺序展示,方便回顾
  • 隐私保护:日记是很私密的东西,要做好加密保护

页面布局设计

日记本的页面我采用了列表布局,每条日记就像一张卡片,展示关键信息。先看看基本结构:

class DiaryPage extends StatelessWidget {
  const DiaryPage({super.key});

  
  Widget build(BuildContext context) {
    final diaries = [
      {'date': DateTime.now(), 'mood': '😊', 
       'title': '美好的一天', 'content': '今天天气很好,完成了很多工作...'},
      {'date': DateTime.now().subtract(const Duration(days: 1)), 
       'mood': '😐', 'title': '平凡的一天', 
       'content': '普通的一天,没什么特别的...'},
    ];

每条日记包含日期、心情、标题、内容四个核心字段。心情用emoji表情来表示,这个设计我觉得特别好,一个表情就能传达很多信息

AppBar设计

return Scaffold(
  appBar: AppBar(
    title: const Text('日记本'),
    actions: [
      IconButton(
        icon: const Icon(Icons.calendar_today),
        onPressed: () {},
      ),
    ],
  ),

AppBar右边放了一个日历图标,点击可以按日期查看日记。这个功能特别实用,想看某一天的日记,直接选日期就行,不用一条条翻。

日记卡片设计

每条日记的卡片设计是这样的:

body: ListView.builder(
  padding: EdgeInsets.all(16.w),
  itemCount: diaries.length,
  itemBuilder: (context, index) {
    final diary = diaries[index];
    return Container(
      margin: EdgeInsets.only(bottom: 16.h),
      padding: EdgeInsets.all(16.w),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(12.r),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withOpacity(0.05),
            blurRadius: 10,
            offset: const Offset(0, 2),
          ),
        ],
      ),

卡片用了白色背景,加了一点阴影效果,看起来有层次感。圆角半径12是我试了很多次才确定的,太小了显得生硬,太大了又不够稳重。

心情和标题展示

child: Column(
  crossAxisAlignment: CrossAxisAlignment.start,
  children: [
    Row(
      children: [
        Text(
          diary['mood'] as String,
          style: TextStyle(fontSize: 32.sp),
        ),
        SizedBox(width: 12.w),
        Expanded(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                diary['title'] as String,
                style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.bold),
              ),
              SizedBox(height: 4.h),
              Text(
                DateFormat('yyyy年MM月dd日').format(diary['date'] as DateTime),
                style: TextStyle(fontSize: 12.sp, color: Colors.grey),
              ),
            ],
          ),
        ),
      ],
    ),

这里把心情emoji放在最显眼的位置,字号32,一眼就能看到。标题和日期放在右边,形成一个清晰的信息层级。日期格式用的是中文格式,更符合阅读习惯。

内容预览

日记内容只显示前几行,点击后才展开全文:

SizedBox(height: 12.h),
Text(
  diary['content'] as String,
  style: TextStyle(fontSize: 14.sp, height: 1.5),
  maxLines: 3,
  overflow: TextOverflow.ellipsis,
),

maxLines: 3限制最多显示3行,overflow: TextOverflow.ellipsis超出部分用省略号。height: 1.5是行高,让文字看起来不那么拥挤,阅读体验更好。

添加日记功能

右下角的浮动按钮用来添加新日记:

floatingActionButton: FloatingActionButton(
  onPressed: () {},
  child: const Icon(Icons.edit),
),

这里用的是编辑图标而不是加号,因为写日记更像是在编辑文字。点击后应该跳转到编辑页面。

编辑页面设计

编辑页面需要包含心情选择、标题输入、内容输入三个部分:

class DiaryEditPage extends StatefulWidget {
  const DiaryEditPage({super.key});

  
  State<DiaryEditPage> createState() => _DiaryEditPageState();
}

class _DiaryEditPageState extends State<DiaryEditPage> {
  String selectedMood = '😊';
  final TextEditingController titleController = TextEditingController();
  final TextEditingController contentController = TextEditingController();
  
  final moods = ['😊', '😄', '😐', '😢', '😡', '😴', '🤔', '😎'];

心情选择器提供了8种常用表情,基本覆盖了日常的各种情绪。不要提供太多选择,太多了反而让人纠结。

心情选择器

Widget buildMoodSelector() {
  return Container(
    padding: EdgeInsets.all(16.w),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text('今天的心情', style: TextStyle(fontSize: 16.sp, fontWeight: FontWeight.bold)),
        SizedBox(height: 12.h),
        Wrap(
          spacing: 12.w,
          children: moods.map((mood) {
            final isSelected = mood == selectedMood;
            return GestureDetector(
              onTap: () => setState(() => selectedMood = mood),
              child: Container(
                padding: EdgeInsets.all(8.w),
                decoration: BoxDecoration(
                  color: isSelected ? Colors.blue.withOpacity(0.1) : null,
                  borderRadius: BorderRadius.circular(8.r),
                  border: isSelected ? Border.all(color: Colors.blue, width: 2) : null,
                ),
                child: Text(mood, style: TextStyle(fontSize: 32.sp)),
              ),
            );
          }).toList(),
        ),
      ],
    ),
  );
}

选中的心情会有蓝色边框和背景色,视觉反馈很重要,让用户知道自己选了什么。

数据存储方案

日记数据需要持久化存储,而且要考虑隐私保护:

import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';
import 'package:crypto/crypto.dart';

class DiaryStorage {
  static const String _key = 'diary_data';
  
  static Future<void> saveDiary(Map<String, dynamic> diary) async {
    final prefs = await SharedPreferences.getInstance();
    final diaries = await loadDiaries();
    diaries.add(diary);
    
    // 简单加密
    final jsonString = jsonEncode(diaries);
    final encrypted = _encrypt(jsonString);
    await prefs.setString(_key, encrypted);
  }
  
  static String _encrypt(String text) {
    // 这里应该用更安全的加密方式
    return base64Encode(utf8.encode(text));
  }
  
  static String _decrypt(String encrypted) {
    return utf8.decode(base64Decode(encrypted));
  }
}

这里用了简单的Base64编码,实际项目中应该用更安全的加密算法,比如AES。日记是很私密的内容,加密保护必不可少

日历视图功能

按日期查看日记是个很实用的功能:

import 'package:table_calendar/table_calendar.dart';

class DiaryCalendarPage extends StatefulWidget {
  const DiaryCalendarPage({super.key});

  
  State<DiaryCalendarPage> createState() => _DiaryCalendarPageState();
}

class _DiaryCalendarPageState extends State<DiaryCalendarPage> {
  DateTime _selectedDay = DateTime.now();
  DateTime _focusedDay = DateTime.now();
  
  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('日历')),
      body: Column(
        children: [
          TableCalendar(
            firstDay: DateTime.utc(2020, 1, 1),
            lastDay: DateTime.utc(2030, 12, 31),
            focusedDay: _focusedDay,
            selectedDayPredicate: (day) => isSameDay(_selectedDay, day),
            onDaySelected: (selectedDay, focusedDay) {
              setState(() {
                _selectedDay = selectedDay;
                _focusedDay = focusedDay;
              });
              // 加载该日期的日记
            },
          ),
        ],
      ),
    );
  }
}

table_calendar包可以快速实现日历功能。选中某一天后,下方显示该天的日记内容。有日记的日期可以用特殊标记,比如小圆点,这样一眼就能看出哪些天写了日记。

搜索和筛选

日记多了之后,搜索功能就很重要了:

List<Map<String, dynamic>> searchDiaries(String query, List<Map<String, dynamic>> diaries) {
  if (query.isEmpty) return diaries;
  
  return diaries.where((diary) {
    final title = diary['title'] as String;
    final content = diary['content'] as String;
    return title.contains(query) || content.contains(query);
  }).toList();
}

List<Map<String, dynamic>> filterByMood(String mood, List<Map<String, dynamic>> diaries) {
  return diaries.where((diary) => diary['mood'] == mood).toList();
}

可以按关键词搜索,也可以按心情筛选。比如想看看自己开心的时候都写了什么,就筛选😊表情的日记。这种回顾功能特别有意思,能看到自己的情绪变化。

导出功能

有时候想把日记导出来备份,或者打印出来:

import 'package:share_plus/share_plus.dart';

Future<void> exportDiary(Map<String, dynamic> diary) async {
  final text = '''
${diary['title']}
${DateFormat('yyyy年MM月dd日').format(diary['date'] as DateTime)}
心情:${diary['mood']}

${diary['content']}
  ''';
  
  await Share.share(text);
}

share_plus包可以调用系统分享功能,把日记分享到其他应用,或者保存为文件。导出功能让数据更安全,不用担心丢失。

统计功能

看看自己写了多少篇日记,哪种心情最多,也是很有意思的:

Map<String, int> getMoodStatistics(List<Map<String, dynamic>> diaries) {
  final stats = <String, int>{};
  for (final diary in diaries) {
    final mood = diary['mood'] as String;
    stats[mood] = (stats[mood] ?? 0) + 1;
  }
  return stats;
}

Widget buildStatistics(Map<String, int> stats) {
  return Column(
    children: stats.entries.map((entry) {
      return ListTile(
        leading: Text(entry.key, style: TextStyle(fontSize: 32.sp)),
        title: Text('${entry.value} 篇'),
        trailing: Text('${(entry.value / stats.values.reduce((a, b) => a + b) * 100).toStringAsFixed(1)}%'),
      );
    }).toList(),
  );
}

统计每种心情出现的次数和占比,可以了解自己的情绪状态。如果发现负面情绪太多,可能需要调整一下生活状态

实际使用体验

我自己用这个日记功能已经有一段时间了,感觉还是挺好的。特别是心情标记这个功能,让我能快速回顾某段时间的情绪状态。

有时候翻看以前的日记,会发现很多有趣的事情。比如某个困扰了很久的问题,现在看来根本不算什么;某个当时觉得很重要的事情,现在已经完全忘记了。时间真的能改变很多东西

不过也发现了一些可以改进的地方:

  • 图片支持:有时候想在日记里插入照片,纯文字不够直观
  • 天气记录:自动记录当天的天气,回顾时更有代入感
  • 地点标记:记录写日记的地点,旅行日记特别有用
  • 标签系统:可以给日记打标签,比如#工作 #生活 #旅行等

隐私保护建议

日记是很私密的内容,隐私保护要做好:

1. 本地加密:所有日记数据都要加密存储,不能明文保存。

2. 密码保护:可以设置一个密码,打开日记本时需要输入密码。

3. 指纹解锁:支持指纹或面部识别,更方便也更安全。

4. 云端备份:如果要云端备份,一定要端到端加密,服务器也看不到内容。

5. 隐藏功能:可以设置某些日记为隐藏,需要额外密码才能查看。

总结

日记功能看起来简单,但要做好需要考虑很多细节。最重要的是要让用户愿意写,愿意坚持写。界面要简洁,操作要流畅,隐私要保护好。

我在开发这个功能的时候,一直在思考怎么让它更好用。后来发现,好的日记应用不是功能最多的,而是最能让人坚持使用的

如果你也在开发类似的功能,建议多从用户角度思考,多试用,多改进。一个好用的日记功能,真的能帮助人们更好地记录和回顾生活。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐