【iOS】基于Realm数据库的记账软件--时间线模块(三)
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数据库的记账软件--时间线模块(三)相关推荐
- 基于Android的个人记账软件的设计与实现
基于Android的个人记账软件的设计与实现 [系统要求] 通过查阅和分析相关资料,应用所学知识与技术,独自完成一套基于Android的个人记账系统.系统开发过程应遵循软件工程思想,任务包括系统架构的 ...
- 基于Android开发的记账软件(附带源码)
该app实现了用户添加删除.用户切换.收入记录.支出记录.查询等功能,适合新手学习.搭建方法请可查看主页中的android相关视频教程. 记账软件文件:url80.ctfile.com/f/25127 ...
- vue基于el-timeline组件实现动态表格时间线
前言 element中表格和时间线组件相信不少同学都用过吧,现在有这么一个需求,利用时间线组件实现不同时间线下的表格数据展示,同时表格表头及表格内的数据也是动态渲染的,效果如下图. 实现效果: 实现思 ...
- 基于mysql+php109在线记账软件
随着计算机网络的日益发展和广泛应用,以及数据库技术的应用,人们传统的一些方式发生了巨大的改变,银行的业务从单一的吸收存款,发放贷款,发展为综合财务业务.顺应这种趋势,本次毕业设计主要是分析.设计和实现 ...
- 数据库mysql面试题 it_【模块三】数据库篇--MySQL面试题☞参考答案
[一]初级 [二]中级 执行过程 [1]客户端向MySQL服务器发送一条查询请求 [2]服务器首先检查查询缓存,如果命中缓存,则立刻返回存储在缓存中的结果.否则进入下一阶段 [3]服务器进行SQL解析 ...
- 基于SQL数据库的装修管理系统计算机毕业设计源码10327
摘 要 信息化社会内需要与之针对性的信息获取途径,但是途径的扩展基本上为人们所努力的方向,由于站在的角度存在偏差,人们经常能够获得不同类型信息,这也是技术最为难以攻克的课题.针对基于sql数据库的装修 ...
- Java项目之家庭记账软件
项目要求 要求实现一个基于文本界面的记账软件,模拟实现一个基于文本界面的<家庭记账软件>,掌握初步的编程技巧和调试技巧. 主要涉及以下知识点: - 局部变量和基本数据类型 - 循环语句 - ...
- Java项目一 家庭记账软件
目录 概述 项目要求 代码 概述 项目来源:B站的尚硅谷java教程 这套视频总的来说还是很良心的,适合快速上手,但是要想深入了解原理的话,深度上还是差一点. 其实这套视频里涉及的练习也谈不上是项目, ...
- [转]软件开发规范—模块开发卷宗(GB8567——88)
做软件开发是有那么一套国准可参照的,当然就是那些文档了,这里列出一下所有软件开发的规范文档: 操作手册 用户手册 软件质量保证计划 软件需求说明书 概要设计说明书 开发进度月报 测试计划文档 测试分析 ...
最新文章
- 20秋PHP作业3,北语20秋《PHP》作业3【标准答案】
- 关于Keil 的快速注释功能,并为其添加快捷键
- 高校c语言程序设计比赛,分秒必争,力争上游,计算机学院举办第八届C语言程序设计挑战杯...
- svm最大间隔函数及目标函数推导
- webstorm前端调用后端接口_一篇前端同学对后端接口的吐槽
- linux脚本实现scp命令自动输入密码和yes/no等确认信息
- Gartner预测:芯片短缺,十大汽车主机厂未来一半都将自主设计芯片
- client mac addr不能开机进不去系统_用asp.net core结合fastdfs打造分布式文件存储系统
- 3天2100万!周杰伦的说好不哭,20万点评Python来分析
- 群里又会python的吗_自从会了Python在群里斗图就没输过,Python批量下载表情包!...
- 下一代的搜索引擎是什么样子?神经网络真的能「死记硬背」吗?
- 恒压板框过滤实验数据处理_中学少见、高考常考的化学实验仪器
- java 148. 排序链表
- QT实现的人机对战五子棋
- 【固件下载】iPhone 全系OS官方固件和自制固件下载和刷机升级方法(更新os4.02自制)
- 生物信息学之抗癌药物反应论文阅读三:ML+PDX
- dis的前缀单词有哪些_以dis为前缀的单词
- 阿里妈妈技术团队5篇论文入选 KDD 2022
- 大数据入门之分布式计算框架Spark(2) -- Spark SQL
- 高性能消息中间件 nsq 解析-介绍