日历时间块布局实现

需求:实现一个日历显示页面如下:

左侧刻度从早上9点开始,到晚上9点结束。以分钟为单位。动态给时间块定位并分配空间。

测试数据一:

var events = [
   {start: 30, end: 150},
   {start: 540, end: 600},
   {start: 560, end: 620}, 
   {start: 610, end: 670}
];
测试数据一

测试数据二:

var events = [
   {start: 30, end: 150}, 
   {start: 540, end: 600}, 
   {start: 550, end: 620}, 
   {start: 560, end: 650}, 
   {start: 630, end: 690},
];
测试数据二

测试数据三:

var events = [
   {start:30,end:670},
   {start:100,end:180},
   {start:180,end:200}, 
   {start:210,end:480}, 
   {start:220,end:490},
   {start:250,end:500}, 
   {start:280,end:510}, 
   {start:540,end:600}, 
   {start:550,end:620}, 
   {start:560,end:650}, 
   {start:630,end:690}, 
   {start:640,end:700},
];
测试数据三

思路:

(1)每一个待办事项都是一个区间,而我们首先要确定的是事情最多的那一分钟处于多少个区间内,以此来计算最小的时间块宽度。
(2)确定了宽度最小的时间块以后,剩下的时间块平分剩下的宽度。
(3)首先想到的是遍历从9:00--21:00的每一分钟内有几个待办事项,需要遍历12*60=720次,显然这种做法太蠢了,我们只需要遍历每个待办事项开始时间点就行了。

image.png

步骤

(1)我们将每一个时间块看成一个区间对象region,用一个数组regionArr读入存放它们。
(2)再建立一个数组beginArr,存放每一个时间块开始的时间点,去掉重复的元素
(3)遍历beginArr里的元素(开始时间点),得出包含该时间点的所有时间块,放入数组,按照开始时间排序。最后将所有数组放入一个大数组crossRegionArr,按照数组内的元素个数排序。
(4)遍历crossRegionArr,取出数组crossRegionArr[0],画出crossRegionArr[0]内的所有时间块。时间块宽度均为屏幕宽度除以crossRegionArr[0]的count,添加到屏幕上,标记为已添加。取出数组crossRegionArr[1],遍历crossRegionArr[1]的元素。如果crossRegionArr[1]中包含已添加到屏幕上的时间块,那么应该去掉该时间块的所占的宽度。剩余的未添加的时间块平分宽度。

以测试数据一为例

image.png

得到排序后的大数组以后,开始绘制时间块。

(1)首先画[540,600),[560,620),画出两个绿色的时间块
(2)画[560,620),[610,670)[560,620)已在屏幕上。减去[560,620)的宽度,[610,670)平分剩余宽度。
(3)画[540,600),已存在,跳过
(4)画[30,150)

image.png

代码实现:

- (void)drawTimeBlock {
    
    NSArray *jsonArr = @[
                         @{@"start":@"30",@"end":@"670"},
                         @{@"start":@"100",@"end":@"180"},
                         @{@"start":@"180",@"end":@"200"},
                         @{@"start":@"210",@"end":@"480"},
                         @{@"start":@"220",@"end":@"490"},
                         @{@"start":@"250",@"end":@"500"},
                         @{@"start":@"280",@"end":@"510"},
                         @{@"start":@"540",@"end":@"600"},
                         @{@"start":@"550",@"end":@"620"},
                         @{@"start":@"560",@"end":@"650"},
                         @{@"start":@"630",@"end":@"690"},
                         @{@"start":@"640",@"end":@"700"},
                         ];
    
    NSMutableArray *regionArr = [NSMutableArray array];
    NSMutableArray *beginArr = [NSMutableArray array];
    
    for (int i=0; i<jsonArr.count; i++) {//将区间读入数组
        Region *region = [[Region alloc] init];
        NSDictionary *dict = jsonArr[i];
        NSString *start = dict[@"start"];
        NSString *end = dict[@"end"];
        region.minNum = start.floatValue;
        region.maxNum = end.floatValue;
        [regionArr addObject:region];
        [beginArr addObject:[NSNumber numberWithFloat:start.floatValue]];
    }
    
    NSMutableArray *crossRegionArr = [NSMutableArray array];
    for (int i=0; i<beginArr.count; i++) {//将区间按重叠区域分组
        NSMutableArray *tempArr = [NSMutableArray array];
        for (int j=0; j<regionArr.count; j++) {
            Region *region = regionArr[j];
            NSNumber *start = beginArr[i];
            if ([region containNum:start.floatValue]) {
                [tempArr addObject:region];
            }
        }
        [tempArr sortUsingComparator:^NSComparisonResult(Region *obj1, Region *obj2) {//按照region起始y值排序
            return obj1.minNum > obj2.minNum;
        }];
        [crossRegionArr addObject:tempArr];
    }
    
    [crossRegionArr sortUsingComparator:^NSComparisonResult(NSArray *obj1, NSArray *obj2) {//数组按照count排序
        return obj1.count < obj2.count;
    }];
    
    for (int i=0; i<crossRegionArr.count; i++) {//遍历排序后的大数组
        NSMutableArray *sortRegionArr = crossRegionArr[i];
        NSInteger devideCount = sortRegionArr.count; //被平分的矩形个数
        CGFloat startX = 0;
        CGFloat endX = self.view.frame.size.width;
        for (int j=0; j<sortRegionArr.count; j++) {//遍历一行region数组
            Region *region = sortRegionArr[j];
            if (!region.associatedView) {//view还没有添加添加,创建view
                
                CGFloat ditance = endX - startX;//计算将要被平分的距离
                
                CGFloat regionX = startX+(j+devideCount-sortRegionArr.count)*ditance/devideCount;
                CGFloat regionY = region.minNum;
                CGFloat regionW = ditance/devideCount;
                CGFloat regionH = region.maxNum - region.minNum;
                
                UIView *addView = [[UIView alloc] initWithFrame:CGRectMake(regionX, regionY,regionW,regionH)];
                addView.backgroundColor = RandColor;
                region.associatedView = addView;
                [self.view addSubview:addView];
            }else{ //view已经添加
                if (region.associatedView.frame.origin.x == startX) {
                    startX += region.associatedView.frame.size.width;
                }else {
                    endX = endX-region.associatedView.frame.size.width;
                }
                devideCount = devideCount - 1;
            }
        }
    }
}

Region对象

@interface Region : NSObject
@property(nonatomic, assign)CGFloat minNum;
@property(nonatomic, assign)CGFloat maxNum;
@property(nonatomic, weak)UIView *associatedView;

- (BOOL)containNum:(CGFloat)num;
@end

@implementation Region
- (BOOL)containNum:(CGFloat)num {
    return (num >= self.minNum && num < self.maxNum);
}
@end

运行结果

三组测试数据运行结果

github地址: https://github.com/liugangios/timeline.git

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,607评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,047评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,496评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,405评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,400评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,479评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,883评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,535评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,743评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,544评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,612评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,309评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,881评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,891评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,136评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,783评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,316评论 2 342

推荐阅读更多精彩内容