【Flutter for OpenHarmony】鸿蒙跨平台训练营 Day 18-19:备忘录提醒与日历视图开发
备忘录提醒设置:允许用户在创建备忘录时选择具体的日期和时间,并内置了时间有效性校验。日历视图:提供了一个全新的底部标签页,通过日历形式直观展示每日的备忘录,方便用户按日期检索和管理。
·
Day 18-19:备忘录提醒与日历视图开发指南
项目仓库:shhzxt/flutter_OpenHarmony
欢迎加入开源鸿蒙跨平台社区: https://openharmonycrossplatform.csdn.net
1. 功能概述
本次更新主要集中在备忘录的时间管理和可视化展示上,新增了两个核心功能:
- 备忘录提醒设置:允许用户在创建备忘录时选择具体的日期和时间,并内置了时间有效性校验。
- 日历视图:提供了一个全新的底部标签页,通过日历形式直观展示每日的备忘录,方便用户按日期检索和管理。
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 进行了改造:
- 底部导航栏:新增中间的“日历” Tab。
- 页面保持与刷新:
- 使用
IndexedStack保持页面状态。 - 强制刷新技巧:为了确保在“备忘录”页新增的数据能即时同步到“日历”页,我们在构建
CalendarPage时传入了UniqueKey()。
注意:这种方式简单有效,但在数据量极大时可能会有性能损耗。更优解是使用状态管理(如 Provider)共享数据源,但对于当前量级应用,此方案性价比最高。CalendarPage(key: UniqueKey()) // 每次切换Tab都会强制重新构建CalendarPage - 使用

4. 效果验证
4.1 新建备忘录
- 点击右下角
+号。 - 点击“设置提醒时间”。
- 尝试选择昨天 -> 提示错误。
- 选择明天上午 10:00 -> 显示成功。
- 保存后,列表卡片出现闹钟图标和时间。

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

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






所有评论(0)