日历时间块布局实现

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

左侧刻度从早上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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容