前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【iOS】基于Realm数据库的记账软件--时间线模块(三)

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

作者头像
MapleYe
发布2020-03-31 11:04:09
8770
发布2020-03-31 11:04:09
举报
文章被收录于专栏:MapleYeMapleYe

1、前言

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

这里写图片描述

这里写图片描述

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

2、时间线搭建

2.1、前言

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

2.2、Cell的设计

先看一下,这个界面的结构,注意View标注的文字,下文说明会用到的。

这里写图片描述

从上图不难看出,一共分为两种Cell:

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

3、数据准备

3.1、模型设计

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

代码语言:javascript
复制
红框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模型。

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

代码语言:javascript
复制
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插入。以此类推,那么实现代码如下:

代码语言:javascript
复制
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数据需要在滚动结束时,需要判断是否切换了月份。

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

代码语言:javascript
复制
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView

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

5、总结

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

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

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、前言
  • 2、时间线搭建
    • 2.1、前言
      • 2.2、Cell的设计
      • 3、数据准备
        • 3.1、模型设计
          • 3.2、数据查询
          • 4、头部数据的切换
            • 4.1、核心思路
              • 4.2、添加监听的位置
              • 5、总结
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档