iOS拨轮交互实现:UIScrollView吸附+Haptic Feedback,3秒录入血压数据
起因给我爸做一个能用的血压记录工具去年我爸确诊高血压医生让每天记录。试了七八个 App要么界面复杂老人不会用要么每次录入要点太多下。有一次他直接拿纸笔记了复诊时掏出一张皱巴巴的纸条递给医生。我当时就决定自己做一个。做出来叫「健康手账」iOS 上架快半年了版本 1.1。核心就解决两件事录入太慢、数据到了手机里医生看不到。拨轮交互UIScrollView 吸附 Haptic Feedback这是我花时间最多的地方。数字键盘录入血压太慢了——高压、低压、心率三个值每个都要点三四下老人容易按错还得删。我的方案是模拟物理转盘的阻尼感用 UIScrollView 做环形滚动区域通过自定义吸附逻辑实现「转到哪停到哪」funcscrollViewWillEndDragging(_scrollView:UIScrollView,withVelocity velocity:CGPoint,targetContentOffset:UnsafeMutablePointerCGPoint){letcellHeight:CGFloat44.0lettargetYtargetContentOffset.pointee.yletsnappedYround(targetY/cellHeight)*cellHeight targetContentOffset.pointee.ysnappedY// 触觉反馈模拟刻度感UIImpactFeedbackGenerator(style:.light).impactOccurred()} 加了HapticFeedback之后转动时有轻微震动我爸说「跟拧收音机一样」。实测录一条血压高压低压心率大概3秒比键盘快3-4倍。 试过三种方案才定下来UIPickerView太丑定制性差CollectionView横向滚动手感不对最后用竖向ScrollView吸附才满意。中间删了两千行代码。 ##PDF就医报告UIGraphicsPDFRenderer自动分页 这个功能的场景很具体——我爸每次复诊医生问「最近血压怎么样」他就说「还行」。我想让他直接递一张纸给医生上面有趋势图和表格。 技术上用UIGraphicsPDFRenderer渲染难点在分页——数据多了表格要自动换页行不能从中间截断。核心判断逻辑大概是这样 swiftfuncrenderTableRows(_rows:[RowData],incontext:UIGraphicsPDFRendererContext){varcurrentY:CGFloatpageMarginTopforrowinrows{letrowHeightcalculateHeight(for:row)// 剩余空间不够一整行强制换页ifcurrentYrowHeightpageHeight-pageMarginBottom{context.beginPage()currentYpageMarginTopdrawTableHeader(at:currentY)// 新页重绘表头}drawRow(row,at:currentY)}} 关键是换页后要重绘表头不然医生翻到第二页看不懂列代表什么。上次复诊医生扫了一眼说「这个整理得清楚」算是验证了方向。 ## 多人档案CoreData用 parent entity 隔离数据 支持建多个档案我手机里有三个我爸、我妈、我自己。 数据层用CoreData多档案隔离的方式是在 schema 里加了一个 Profile entity 作为 parent所有的 BloodPressureRecord、WeightRecord、StatusStamp 都通过 relationship 挂在某个Profile下面。查询的时候用NSPredicate按 profile 过滤 NSPredicate(format:profile %,currentProfile) 没用多个 persistent store 的方案——太重了而且将来如果做导出功能单个SQLite文件比较好处理。 所有数据存在本地没有服务器没有账号。健康数据太敏感我不想碰用户隐私也不想维护后端。代价是没法跨设备同步但对于「每天固定用一台手机记录」的场景够用。 ## 状态印章离散事件和时间序列数据的关联 除了数值记录做了一组状态印章——吃药、运动、饮酒、熬夜。每天点一下像盖章。 数据模型上StatusStamp 是独立 entity字段很简单type枚举、timestamp、profile。它和 BloodPressureRecord 没有直接 relationship关联展示是在趋势图渲染时按时间轴做的——取当天的所有 stamp在折线图对应日期的X轴位置画小图标。 这样做的好处是 stamp 和数值记录完全解耦将来加新的 stamp 类型不需要动血压/体重的 schema。坏处是查询「吃药日 vs 未吃药日的血压均值对比」时要在内存里做 join数据量大了可能有性能问题——不过对于个人用户几年的数据量也就几千条目前没遇到瓶颈。 ## 目前状态-2024年上架当前版本1.1--买断制不搞订阅。慢病记录这种东西用户可能用好几年订阅不公平--下载量说实话不多没怎么推广过--日活不高但留存还行——毕竟是每天都要用的工具--鸿蒙版在计划中ArkUI写数据录入界面应该挺合适 ## 一个想讨论的问题 做这种长期记录类工具App你们会选CoreData还是SQLite比如GRDB/FMDB 我选CoreData主要因为和NSFetchedResultsController配合做列表刷新很省事iCloud 同步将来也有现成方案。但也遇到了烦心事——轻量级迁移lightweight migration在加新 entity 时没问题改字段类型就容易翻车有一次测试阶段数据全丢了。如果用SQLite自己管 schema 版本至少迁移逻辑是透明可控的。 你们怎么选的有没有踩过类似的坑