需求:实现一个日历显示页面如下:
左侧刻度从早上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
次,显然这种做法太蠢了,我们只需要遍历每个待办事项开始时间点就行了。
步骤
(1)我们将每一个时间块看成一个区间对象region,用一个数组regionArr
读入存放它们。
(2)再建立一个数组beginArr
,存放每一个时间块开始的时间点,去掉重复的元素
(3)遍历beginArr
里的元素(开始时间点),得出包含该时间点的所有时间块,放入数组,按照开始时间排序。最后将所有数组放入一个大数组crossRegionArr
,按照数组内的元素个数排序。
(4)遍历crossRegionArr
,取出数组crossRegionArr[0]
,画出crossRegionArr[0]
内的所有时间块。时间块宽度均为屏幕宽度除以crossRegionArr[0]
的count,添加到屏幕上,标记为已添加。取出数组crossRegionArr[1]
,遍历crossRegionArr[1]
的元素。如果crossRegionArr[1]
中包含已添加到屏幕上的时间块,那么应该去掉该时间块的所占的宽度。剩余的未添加的时间块平分宽度。
以测试数据一为例
得到排序后的大数组以后,开始绘制时间块。
(1)首先画[540,600),[560,620)
,画出两个绿色的时间块
(2)画[560,620),[610,670)
。[560,620)
已在屏幕上。减去[560,620)
的宽度,[610,670)
平分剩余宽度。
(3)画[540,600)
,已存在,跳过
(4)画[30,150)
代码实现:
- (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