酒店预订日历控件的实现

前段时间项目中牵涉到一个日历控件的自定义实现,其样貌如下图所示。

UI图设计

由于项目中使用到这个日历的地方还有几个,且下面不一定有取消确定按钮这些,想来想去还是自己先封装一个整体的日历控件的好,说干就干,封装的主要包含日历头部的左右翻页按钮,中间月份显示以及日历主体部分,至于其他的取消确定按钮这些都可以二次封装或者固定在页面上等等均可,视情况而定咯。

日历上面的头部简单不作说明,主要来说一下主体部分的实现思路。
主体部分分为周日到周六七天横排和下面当前月份的所有天数排列,有的月份是28天,有的是30天,还有的是31天,所以可以知道的是日历主题部分的高度是不固定的,如果是28天,只需要排列4行就可以排列完(假设第一天是周日),再假设当月有31天,第一天周六,那么久需要6行来排列。

根据日历主体的特性,我会使用UICollectionView来实现当前月份中所有天数的排列。collectionView要分为两组,第一组用来显示日 一 二 三 四 五 六的排列;第二组即为一个个的小方格子(或许不方),用来显示日。为了简便或者是个人编程习惯问题,习惯用xib来搞,那么下面就来展示一下xib布局的效果(两个collectionCell):

collectionCell---1
collectionCell---2

接下来就是要创建自定义view了,这个view我也是使用xib来实现的,xib布局图如下:

HmSearchCalendar.xib

既然是日历,在view初始化的时候你就要知道当前日期(即今天的年份、月份、日期),同时你也要知道当前月份一共有多少天,本月的第一天是周几,上个月在本月应该显示多少个等这些基本的数据。以下为声明的成员变量(注释也很清楚):

@property (nonatomic, assign) int totalDayThisMonth;    // 本月总天数
@property (nonatomic, assign) int firstWeekDay;         // 本月第一天周几
@property (nonatomic, assign) int lastSum;      // = firstWeekDay  显示上个月格子数
@property (nonatomic, assign) int sumDays;      // = totalDayThisMonth + lastSum + nextSum  显示总格子数

@property (nonatomic, assign) int currentShowYear;  // 当前选择的年份
@property (nonatomic, assign) int currentShowMonth; // 当前选择的月份

@property (nonatomic, assign) int nowYears; // 今天所属年份
@property (nonatomic, assign) int nowMonth; // 今天所属月份
@property (nonatomic, assign) int nowDay;   // 今天

@property (nonatomic, assign) int selectCheckInYear;    // 选择入住年份
@property (nonatomic, assign) int selectCheckInMonth;   // 选择入住月份
@property (nonatomic, assign) int selectCheckInDay;     // 选择入住天    默认当天

@property (nonatomic, assign) int selectCheckOutYear;   // 选择退房年份
@property (nonatomic, assign) int selectCheckOutMonth;  // 选择退房月份
@property (nonatomic, assign) int selectCheckOutDay;    // 选择退房天    默认当天的下一天

@property (nonatomic, assign) int selectCheckInOrOut;   // 选择入住或退房 0:选择结束(再点击选择为入住)  1:入住选择结束(再点击选择为退房)   默认0

@property (nonatomic, strong) NSDateComponents *comps;
@property (nonatomic, strong) NSCalendar *calendar;
@property (nonatomic, strong) NSDateFormatter *formatter;

@property (nonatomic, strong) HmSearchCalendarHeaderCollectionCell *cellHeader;
@property (nonatomic, strong) HmSearchCalendarBodyCollectionCell *cellBody;

在view初始化的时候,要遵循collectionView代理,并初始化成员变量的值。然后根据具体的值来排列布局view,除此之外,还要区分过去时间和未来时间,选择的入住时间和退房时间的先后等问题,详情见代码。

内部实现有些地方使用文字一时半会也说不清,不懂的地方可以查看代码,再者就说说对外暴露的方法和成员变量吧

@property (nonatomic, copy) void (^selectDateSuccess)(NSString *startDate, NSString *endDate, int nightCount);
@property (nonatomic, copy) void (^setNormalValue)(NSString *startDate, NSString *endDate, int nightCount);
@property (nonatomic, copy) void (^collectionViewHeightChanged)(CGFloat height);

@property (nonatomic, strong) NSString *startDate;  // 默认入住日期
@property (nonatomic, strong) NSString *endDate;    // 默认离店日期

/// 整体背景颜色(默认reb:240,240,240)
@property (nonatomic, strong) UIColor *backColor;

以上代码为在.h文件中声明的block和成员变量等,根据名称也能判断出个大概:
selectDateSuccessblock主要就是在用户选择了入住日期和退房日期后返回的开始时间和结束时间以及一共多少个晚上。
setNormalValueblock主要是在view刚刚初始化之后返回默认的开始时间和结束时间以及一共多少个晚上(默认是当天入住,明天退房,共一个晚上;不过有时候需要在初始化的时候入住时间和退房时间是指定的日期,设置默认返回主要是为了在外界显示所用)。
collectionViewHeightChangedblock主要就是返回当前日历view的高度。
startDate设置默认显示的开始时间,不设置即为今天
endDate设置默认显示的结束时间,不设置即为明天
backColor这是背景颜色
类似于backColor这样的成员变量可以在用到的时候自行定义,我这里只是设置了一个背景色,其他的没有具体设置。

至于使用那就更简单咯

  1. 引入头文件
  2. 初始化
  3. 添加在view上并实现block即可
    示例代码如下:
self.calendarV = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([HmSearchCalendar class]) owner:self options:nil].lastObject;
    _calendarV.frame = CGRectMake(20, 100, kScreenWidth - 40, 300); // 高度300为随意设置,在初始化后会返回高度再次更新
    Weak(self);
    _calendarV.setNormalValue = ^(NSString *startDate, NSString *endDate, int nightCount) {
        NSLog(@"默认的入住日期是:%@,退房日期是:%@,共%d晚", startDate, endDate, nightCount);
    };
    _calendarV.selectDateSuccess = ^(NSString *startDate, NSString *endDate, int nightCount) {
        NSLog(@"选中的入住日期是:%@,退房日期是:%@,共%d晚", startDate, endDate, nightCount);
    };
    _calendarV.collectionViewHeightChanged = ^(CGFloat height) {
        NSLog(@"我收到通知回调了,高度是:%f", height);
        wself.calendarV.hm_height = height;
    };
    [self.view addSubview:_calendarV];

效果图跟UI一样,我就不再截图了,如有需要的小伙伴可以下载代码使用。
代码传送门

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

推荐阅读更多精彩内容