Day 18-19:备忘录提醒与日历视图开发指南

项目仓库:shhzxt/flutter_OpenHarmony

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

1. 功能概述

本次更新主要集中在备忘录的时间管理和可视化展示上,新增了两个核心功能:

  1. 备忘录提醒设置:允许用户在创建备忘录时选择具体的日期和时间,并内置了时间有效性校验。
  2. 日历视图:提供了一个全新的底部标签页,通过日历形式直观展示每日的备忘录,方便用户按日期检索和管理。

2. 技术栈与依赖

为了实现上述功能,我们引入了以下 Flutter 插件:

  • table_calendar: ^3.0.9
    • 用途:提供高度可定制的日历组件,支持按月视图展示、事件标记、日期选择回调等。
    • 选择理由:社区活跃度高,功能丰富,文档完善,是 Flutter 生态中最流行的日历插件。
  • intl: ^0.18.1
    • 用途:用于日期和时间的格式化(如 yyyy-MM-dd HH:mm)。
    • 选择理由:Flutter 官方提供的国际化和本地化工具,标准且可靠。

pubspec.yaml 中的配置如下:

dependencies:
  table_calendar: ^3.0.9
  intl: ^0.18.1

3. 核心功能实现详解

3.1 备忘录提醒设置 (MemoPage)

日期选择 时分选择
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
3.1.1 模型更新

虽然 Memo 模型本身已包含 reminderTime 字段,但我们在 _addMemo 方法中增加了可选参数,以便在创建时传入。

3.1.2 UI 交互设计

在“新建备忘录”弹窗 (AlertDialog) 中,我们使用了 StatefulBuilder 来管理弹窗内部的状态(因为 showDialog 本身是无状态的)。

  • 日期与时间选择器

    • 使用 showDatePicker 选择日期。
    • 使用 showTimePicker 选择时间。
    • 两者结合生成最终的 DateTime 对象。
  • 逻辑校验

    • 规则:选择的时间必须晚于当前时间 (DateTime.now())。
    • 反馈:如果用户选择了过去的时间,通过 SnackBar 弹出提示“提醒时间必须晚于当前时间”,并拒绝保存该时间。
  • 代码片段

// 唤起日期选择器
final date = await showDatePicker(
  context: context,
  initialDate: selectedDate ?? now,
  firstDate: now,
  lastDate: DateTime(now.year + 5),
);

// 唤起时间选择器
if (date != null) {
  final time = await showTimePicker(
    context: context,
    initialTime: selectedTime ?? TimeOfDay.now(),
  );
  
  // 校验逻辑
  final dateTime = DateTime(...);
  if (dateTime.isAfter(DateTime.now())) {
    setState(() { ... }); // 更新选中状态
  } else {
    // 错误提示
  }
}

3.2 日历视图 (CalendarPage)

3.2.1 数据加载与映射

日历组件需要知道每一天有哪些事件(备忘录)。我们需要将扁平的 List<Memo> 转换为 Map<DateTime, List<Memo>> 结构。

  • 映射规则
    • 优先使用 reminderTime(提醒时间)作为事件日期。
    • 如果未设置提醒时间,则降级使用 createdTime(创建时间)。
    • 关键点TableCalendar 比较日期时会精确到时分秒,因此作为 Key 的 DateTime 必须标准化(去除时间部分,只保留年月日),否则会导致事件无法匹配到当天的格子上。
// 日期标准化处理
final dateKey = DateTime(date.year, date.month, date.day);
if (events[dateKey] == null) {
  events[dateKey] = [];
}
events[dateKey]!.add(memo);
3.2.2 界面构建

使用 TableCalendar 构建月视图:

  • eventLoader:绑定上述生成的 Map,自动在日期下方显示标记点(Marker)。
  • onDaySelected:点击日期时,更新 _selectedDay 并刷新下方的列表视图。
  • CalendarStyle:定制了选中日期(深紫色)和今日(蓝色)的样式。

下方复用了 ListView 展示选中日期的备忘录列表,卡片样式与主页保持一致,但额外强调了时间显示。

在这里插入图片描述

3.3 主页导航集成 (HomePage)

为了让用户方便地访问日历,我们对 HomePage 进行了改造:

  1. 底部导航栏:新增中间的“日历” Tab。
  2. 页面保持与刷新
    • 使用 IndexedStack 保持页面状态。
    • 强制刷新技巧:为了确保在“备忘录”页新增的数据能即时同步到“日历”页,我们在构建 CalendarPage 时传入了 UniqueKey()
    CalendarPage(key: UniqueKey()) // 每次切换Tab都会强制重新构建CalendarPage
    
    注意:这种方式简单有效,但在数据量极大时可能会有性能损耗。更优解是使用状态管理(如 Provider)共享数据源,但对于当前量级应用,此方案性价比最高。

在这里插入图片描述

4. 效果验证

4.1 新建备忘录

  1. 点击右下角 + 号。
  2. 点击“设置提醒时间”。
  3. 尝试选择昨天 -> 提示错误。
  4. 选择明天上午 10:00 -> 显示成功。
  5. 保存后,列表卡片出现闹钟图标和时间。
    在这里插入图片描述

4.2 日历查看

  1. 切换到底部“日历”标签。
  2. 日历上明天对应的日期下方出现小圆点。
  3. 点击该日期,下方列表显示刚才创建的备忘录。

在这里插入图片描述

5. 后续优化方向

  1. 本地通知推送:目前仅记录了时间,尚未集成系统级的本地通知(Local Notifications),后续可引入 flutter_local_notifications 实现到点弹窗提醒。
  2. 数据共享优化:引入 Provider 或 Riverpod 将 Memo 数据提升为全局状态,避免页面切换时的重复加载。
  3. 多视图支持:增加周视图或日程视图,适应更多使用场景。
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐