在网站和iOS应用开发领域,沉浸式编码是一种常见的工作方式。目前已有两款应用成功上架App Store。
首款上架的应用名为Brush Tracker。这款应用旨在帮助用户追踪日常刷牙习惯,通过细微的激励提示保持行为一致性,从而维护口腔清洁。关于该应用的完整开发与上架过程,曾有一篇详细文章进行过阐述。
近期,开发者为Brush Tracker规划了一项新功能:一个类似日历的网格视图,用于直观展示用户每月的刷牙坚持情况。本文将详细介绍如何借助Cursor AI工具,并结合必要的手动调整,最终实现这一功能。
初始需求描述
设想的界面类似于常见的习惯追踪应用中的网格,或者GitHub上的贡献度图表。
开发过程从Cursor的“计划模式”开始。当需要添加新功能或进行重大改动时,这一模式被证明非常高效。开发者只需定义功能或解释任务,Cursor便会生成一份详细的实施计划。
以下是在计划模式中使用的确切提示词:
需要添加一个日历式网格来追踪用户完成刷牙的天数。网格由方块组成,每个方块代表一个月中的一天。网格中方块的初始状态为黑色。如果用户完成了当天所有刷牙次数,方块显示为绿色;如果部分完成,则显示为浅绿色。例如,用户设定的每日刷牙次数为2次。若某天只完成1次,对应方块应为浅绿色;若完成2次,则该天方块应为绿色。用户可通过点击屏幕左上角的日历图标访问此网格。
在最终确定实施计划前,Cursor提出了两个问题以澄清细节。这一步骤非常有用,因为它表明工具会主动寻求澄清,而非自行做出假设。
Cursor提出的两个问题是:
- 日历网格是仅显示当前月份,还是允许在月份之间导航?
- 追踪是从今天开始向前计算,还是也显示过去的日子(这些日子将显示为黑色)?
开发者指示Cursor允许月份导航,并将当月已过去的日期显示为黑色。随后,Cursor创建了一个Markdown文件,概述了详细的实施计划。
该计划详细解释了功能的实现方式,并包含一系列可执行的任务项。
Cursor列出的待办事项:
-
扩展BrushModel以持久化追踪历史每日刷牙数据
-
创建CalendarGridView组件,包含月份网格和颜色编码的方块
-
在ContentView的左上角添加日历图标按钮
-
使用sheet弹窗方式将CalendarGridView集成到ContentView中
接下来,开发者要求Cursor执行该计划。虽然可以在执行前修改计划,但此次选择完全按照Cursor的原始大纲进行。
实现过程一次成功,功能可以直接在Xcode模拟器中测试。然而,初始设计效果不佳:

注:本文所有图片均来自应用Brush Tracker的截图。
由于Xcode模拟器不再包含日期和时间设置,开发者通过更改Mac的系统日期来测试网格颜色在不同日期的更新情况。
对初始样式不满意,于是向Cursor提出了重新设计网格的提示:
需要改变网格的设计风格。理想效果类似于GitHub贡献度网格。此外,代表日期的方块中不要显示日期数字。
这个提示并未达到预期效果。它只移除了日期数字:

随后,开发者分享了一张目标网格风格的示例图片,要求Cursor进行类似设计。
新设计更接近设想,但存在结构性问题。方块太小,在布局中缩放效果不好:

这个设计存在两个主要问题:
- 每个月显示42个方块(与实际天数不符)。
- 方块尺寸过小。
针对第一个问题,向Cursor发出了以下修正提示:
当前实现中,十一月和十二月都显示了42个方块。网格中的方块代表一个月中的天数,因此方块数量必须与该月的实际天数相等。
第二个问题相对简单,可以通过调整参数值来解决。例如,网格中方块的大小可以通过squareSize参数修改:
struct DaySquare: View {
let isToday: Bool
let isCurrentMonth: Bool
let brushCount: Int
let brushesPerDay: Int
private let squareSize: CGFloat = 8 // 修改此参数
将方块尺寸调整为32后,网格效果如下:

另一个可通过参数调整的问题是行间距。
在上面的截图中,行与行之间似乎没有空隙。这可以通过增加行间距来改变。
此外,希望每行显示8个方块(即代表8天),并调整行间距。
所有这些调整都可以在以下代码片段中完成:
// 日历网格 - 精简GitHub风格
LazyVGrid(columns: Array(repeating: GridItem(.flexible(), spacing: 0.2), count: 8), spacing: 0) {
ForEach(Array(calendarDays.enumerated()), id: .offset) { index, dayInfo in
DaySquare(
isToday: dayInfo.isToday,
isCurrentMonth: dayInfo.isCurrentMonth,
brushCount: dayInfo.brushCount,
brushesPerDay: model.brushesPerDay,
size: 32
)
.padding(.bottom, 3)
}
}
spacing控制一行中方块之间的间距padding控制行与行之间的间距count控制每行显示的方块数量
对上述代码片段中的参数值进行一番调试后,得到了如下网格:

如果用户在某天完成了所有刷牙次数,对应方块显示为亮绿色。如果部分完成,则该天方块显示为淡绿色。其他日期显示为黑色,当天日期用一个白色边框标出。
在实现了追踪过往日期的功能后,很自然地想到为连续打卡添加通知提醒。通过以下提示词要求Cursor实现此功能:
添加通知功能:当用户连续10天、20天和30天完成所有刷牙次数时发出提醒。同时,当用户在一个月内每天都完成所有刷牙次数时,添加月度成就通知。通知内容应具有鼓励性和激励性。
最终实现的网格设计或许并非最佳,但足以清晰传达信息。用户查看此网格时,能立即了解自己的刷牙频率概况。
借助Cursor的协助和部分手动调整,该功能在几小时内便得以实现并准备发布。截至本文撰写时,该版本仍在App Store审核中。读者阅读此文时,更新可能已经发布。如需查看或试用此应用,可访问Brush Tracker的App Store链接。
