美文网首页
日历时间块布局实现

日历时间块布局实现

作者: 檀羽冲 | 来源:发表于2017-12-08 18:23 被阅读337次

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

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

相关文章

  • 日历时间块布局实现

    需求:实现一个日历显示页面如下: 左侧刻度从早上9点开始,到晚上9点结束。以分钟为单位。动态给时间块定位并分配空间...

  • flex 布局

    flex 布局特点 块级布局侧重垂直方向、行内布局侧重水平方向,flex布局与方向无关 flex布局可以实现空间自...

  • flex布局

    Flex布局特点 块级布局侧重垂直方向、行内布局侧重水平方向,flex布局是与方向无关的。 flex布局可以实现空...

  • 自定义日历控件

    Android自定义日历控件(继承系统控件实现) 主要步骤 编写布局 继承LinearLayout设置子控件 设置...

  • HTML第二课

    CSS控制div样式 1.浮动布局:float 实现两个布局并行显示 2.清除浮动布局 清除本块布局被覆盖的float

  • Android开发之头部悬浮的上拉加载,下拉刷新的列表

    时间悬浮 带时间戳的列表,要求时间悬浮顶部,动态替换顶部时间如下图,如下图, 布局实现 多布局实现,时间悬浮为一个...

  • HTML 5列表、块和布局;学习笔记(二)

    列表、块和布局 列表 块 布局 使用 元素布局 使用 元素布局

  • CSS Flex实现各种布局

    实现两栏布局 实现栅格布局 实现三栏布局 附录 双飞翼布局 圣杯布局

  • 瀑布流布局

    瀑布流,又称瀑布流式布局。这种布局适合于小数据块,每个数据块内容相近且没有侧重。 实现思路:管理一个数组,在里面存...

  • CSS简单布局任务

    实现一个单栏布局 实现一个三栏布局 实现圣杯布局 实现双飞翼布局 实现效果

网友评论

      本文标题:日历时间块布局实现

      本文链接:https://www.haomeiwen.com/subject/uqpeixtx.html