1、前言

接下来,我们将开始搭建时间线界面。该模块是界面展示中最大的难点–时间线布局。那么,我们先来看看效果图,因为gif上传后,动不了。所以在这里用几张截图和文字简单的描述一下,具体效果大家可下载项目自行查看~


从图一滚动到图二时,头部从7月的数据变成6月的账单数据。

2、时间线搭建

2.1、前言

这个时间线界面是仿照口袋记账的,一开始没有头绪的时候,就把自己的手机越狱了,然后通过Reveal进行查看其布局,具体Reveal的用法,可以看我之前的博客。传送门

2.2、Cell的设计

先看一下,这个界面的结构,注意View标注的文字,下文说明会用到的。
从上图不难看出,一共分为两种Cell:

  • 显示账单信息的Cell,如红框所示,显示账单类型,金额
  • 显示当天日期的一个汇总,如蓝框所示,显示该日的一个总收入和总支出

3、数据准备

3.1、模型设计

由于我们的Cell是有两种类型的,那么我们需要通过模型去控制Cell的产生以及赋值。因此,我们需要一个type来区分是什么类型的Cell,通过Type去加载对应的Cell。模型设计如下:

红框Cell模型
/// 时间线模型
@interface MPTimeLineModel : NSObject/// 模型的类型
@property (nonatomic, assign) TimeLineType type;
/// 账单模型
@property (nonatomic, strong) MPBillModel *bill;
/// 时间字符串
@property (nonatomic, copy) NSString *dateStr;
/// 一天内的账单模型
@property (nonatomic, strong) MPDayBillModel *dayBill;
@end蓝框Cell模型
/// 一天的消费模型
@interface MPDayBillModel : NSObject
/// 日期字符串
@property (nonatomic, copy) NSString *dateStr;
/// 收入
@property (nonatomic, assign) double income;
///支出
@property (nonatomic, assign) double outcome;
@end

3.2、数据查询

由时间线的布局特性,要求我们要以“dateStr”字段进行进行降序排序(即最新的日期放在最前面)。然后再以“日”为单位,将同一日的账单的归类在一起,整合成MPDayBillModel模型。

一、查询当前账本的所有账单并排序

MPBillManager下的方法
- (RLMResults *)getBillsInCurrentBook
{MPBookModel *book = [[MPBookManager shareManager] getCurrentBook];RLMResults *results = [MPBillModel objectsWhere:@"book=%@", book];// 返回排序后的结果集return [self sortTheResultsByDate:results];
}- (RLMResults *)sortTheResultsByDate:(RLMResults *)results
{// 首先根据dateStr(账单时间)进行排序RLMSortDescriptor *desc1 = [RLMSortDescriptor sortDescriptorWithKeyPath:@"dateStr" ascending:NO];// 再根据recordDate(记录时间)进行排序RLMSortDescriptor *desc2 = [RLMSortDescriptor sortDescriptorWithKeyPath:@"recordDate" ascending:NO];return [results sortedResultsUsingDescriptors:@[desc1, desc2]];
}

二、以“日”为单位,开始整合数据模型,这里的实现有点繁琐,但是逻辑是不难的。核心思路是找到同一天的所有账单后,创建一个MPDayBillModel插入。以此类推,那么实现代码如下:

MPTimeLineModel的类方法
+ (NSMutableArray *)timeLineArrayWithResults:(RLMResults *)results
{NSMutableArray *modelArray = [NSMutableArray array];NSMutableArray *billInSameDay = [NSMutableArray array];for(int i = 0; i < results.count; i++){MPBillModel *bill = results[i];// 当数组为空时,直接添加元素if(billInSameDay.count == 0){[billInSameDay addObject:bill];}else{// 将日期相同的账单,放在同一个数组中MPBillModel *lastOj = billInSameDay.lastObject;if([bill.dateStr isEqualToString:lastOj.dateStr]){[billInSameDay addObject:bill];}else{// 创建Day类型的模型[modelArray addObject:[self getDayItemWithBillArray:billInSameDay dateStr:lastOj.dateStr]];// 生成Normal类型的模型for (MPBillModel *bill in billInSameDay){MPTimeLineModel *model = [[MPTimeLineModel alloc] init];model.bill = bill;model.type = TimeLineNormalItem;[modelArray addObject:model];}// 重新开始分类[billInSameDay removeAllObjects];[billInSameDay addObject:bill];}}}if(billInSameDay.count != 0){MPBillModel *bill = billInSameDay.firstObject;[modelArray addObject:[self getDayItemWithBillArray:billInSameDay dateStr:bill.dateStr]];// 生成Normal类型的模型for (MPBillModel *bill in billInSameDay){MPTimeLineModel *model = [[MPTimeLineModel alloc] init];model.bill = bill;model.type = TimeLineNormalItem;[modelArray addObject:model];}}return modelArray;
}

4、头部数据的切换

4.1、核心思路

这里有一个很重要的效果,就是当6月的节点滑动到头部时,头部的header将显示6月的总收入以及总支出数据。那么,我们就需要在月份节点与头部View相交的时候,做数据复制。那么,沿着这个思路,我的解决方案就是,首先将月份节点,头部View转为同一坐标系,然后通过判断是否相进行处理。

4.2、添加监听的位置

自然地,我们需要在scrollView滚动的时候进行实时监听。此外,当scrollView快速滚动时,scrollViewDidScroll调用的不够频繁,因此里面计算header数据需要在滚动结束时,需要判断是否切换了月份。

所以我们需要在以下两个方法进行判断:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView

判断的方式稍有不同,具体的实现方式请看MPBillTableViewController的上述的两个scrollView代理方法

5、总结

该时间线的实现共有两个难点:

  • 难点一,数据查询后,生成业务需求的模型
  • 难点二,头部View的数据监听

但只要掌握其核心思路,再去阅读代码,我相信大家都能看的懂的~

【iOS】基于Realm数据库的记账软件--时间线模块(三)相关推荐

  1. 基于Android的个人记账软件的设计与实现

    基于Android的个人记账软件的设计与实现 [系统要求] 通过查阅和分析相关资料,应用所学知识与技术,独自完成一套基于Android的个人记账系统.系统开发过程应遵循软件工程思想,任务包括系统架构的 ...

  2. 基于Android开发的记账软件(附带源码)

    该app实现了用户添加删除.用户切换.收入记录.支出记录.查询等功能,适合新手学习.搭建方法请可查看主页中的android相关视频教程. 记账软件文件:url80.ctfile.com/f/25127 ...

  3. vue基于el-timeline组件实现动态表格时间线

    前言 element中表格和时间线组件相信不少同学都用过吧,现在有这么一个需求,利用时间线组件实现不同时间线下的表格数据展示,同时表格表头及表格内的数据也是动态渲染的,效果如下图. 实现效果: 实现思 ...

  4. 基于mysql+php109在线记账软件

    随着计算机网络的日益发展和广泛应用,以及数据库技术的应用,人们传统的一些方式发生了巨大的改变,银行的业务从单一的吸收存款,发放贷款,发展为综合财务业务.顺应这种趋势,本次毕业设计主要是分析.设计和实现 ...

  5. 数据库mysql面试题 it_【模块三】数据库篇--MySQL面试题☞参考答案

    [一]初级 [二]中级 执行过程 [1]客户端向MySQL服务器发送一条查询请求 [2]服务器首先检查查询缓存,如果命中缓存,则立刻返回存储在缓存中的结果.否则进入下一阶段 [3]服务器进行SQL解析 ...

  6. 基于SQL数据库的装修管理系统计算机毕业设计源码10327

    摘 要 信息化社会内需要与之针对性的信息获取途径,但是途径的扩展基本上为人们所努力的方向,由于站在的角度存在偏差,人们经常能够获得不同类型信息,这也是技术最为难以攻克的课题.针对基于sql数据库的装修 ...

  7. Java项目之家庭记账软件

    项目要求 要求实现一个基于文本界面的记账软件,模拟实现一个基于文本界面的<家庭记账软件>,掌握初步的编程技巧和调试技巧. 主要涉及以下知识点: - 局部变量和基本数据类型 - 循环语句 - ...

  8. Java项目一 家庭记账软件

    目录 概述 项目要求 代码 概述 项目来源:B站的尚硅谷java教程 这套视频总的来说还是很良心的,适合快速上手,但是要想深入了解原理的话,深度上还是差一点. 其实这套视频里涉及的练习也谈不上是项目, ...

  9. [转]软件开发规范—模块开发卷宗(GB8567——88)

    做软件开发是有那么一套国准可参照的,当然就是那些文档了,这里列出一下所有软件开发的规范文档: 操作手册 用户手册 软件质量保证计划 软件需求说明书 概要设计说明书 开发进度月报 测试计划文档 测试分析 ...

最新文章

  1. 20秋PHP作业3,北语20秋《PHP》作业3【标准答案】
  2. 关于Keil 的快速注释功能,并为其添加快捷键
  3. 高校c语言程序设计比赛,分秒必争,力争上游,计算机学院举办第八届C语言程序设计挑战杯...
  4. svm最大间隔函数及目标函数推导
  5. webstorm前端调用后端接口_一篇前端同学对后端接口的吐槽
  6. linux脚本实现scp命令自动输入密码和yes/no等确认信息
  7. Gartner预测:芯片短缺,十大汽车主机厂未来一半都将自主设计芯片
  8. client mac addr不能开机进不去系统_用asp.net core结合fastdfs打造分布式文件存储系统
  9. 3天2100万!周杰伦的说好不哭,20万点评Python来分析
  10. 群里又会python的吗_自从会了Python在群里斗图就没输过,Python批量下载表情包!...
  11. 下一代的搜索引擎是什么样子?神经网络真的能「死记硬背」吗?
  12. 恒压板框过滤实验数据处理_中学少见、高考常考的化学实验仪器
  13. java 148. 排序链表
  14. QT实现的人机对战五子棋
  15. 【固件下载】iPhone 全系OS官方固件和自制固件下载和刷机升级方法(更新os4.02自制)
  16. 生物信息学之抗癌药物反应论文阅读三:ML+PDX
  17. dis的前缀单词有哪些_以dis为前缀的单词
  18. 阿里妈妈技术团队5篇论文入选 KDD 2022
  19. 大数据入门之分布式计算框架Spark(2) -- Spark SQL
  20. 高性能消息中间件 nsq 解析-介绍

热门文章

  1. oracle建表的时候同时创建主键,外键,注释,约束,索引
  2. kaos linux 包管理,KaOS v2018.12版正式发布附下载-独立的 Linux 发行版
  3. spring源码解析(一)迈向学习spring之路
  4. 基于改进YOLOv7&OpenCV的行人过马路速度与交通灯实时监测系统(源码&教程)
  5. 服务器维护的几个注意点
  6. SpringMVC静态资源配置
  7. oracle的farsync,Oracle 12c 新特性 Active Data Guard Far Sync
  8. 无线路由速度简单解释
  9. LTE 随机接入 --(1)流程
  10. 智能化引领中国铁路发展