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

2017-09-06  本文已影响0人  mapleYe

1、前言

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

这里写图片描述
这里写图片描述

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

2、时间线搭建

2.1、前言

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

2.2、Cell的设计

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

从上图不难看出,一共分为两种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、总结

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

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

github地址

https://github.com/maple1994/MPTally
请顺手给一个start哦,哈哈

上一篇下一篇

猜你喜欢

热点阅读