iOS开发类携程日历,价格日历,单选,多选,可选不可选

之前开发也遇到过酒店,火车票日历,我用了一款第三方软件,前期还行,随着后期功能(业务)增多,就不好使了,特别是那个循环架构,年 月 日这种的,修改起来特别麻烦。
新增业务例如:
1、价格日历,景点价格日历,机票价格日历
2、基地日历,我们基地价格分批次的 1-8天 110元/天,9-20天100 ,21-30天90,这就要求选择开始日期后,重新刷新数据,只能选择天数区域内的时间。
3、活动日历,活动不是每天搞,隔三差五的,一句话就是可点不可点,传日期输入,处理后展示出来。

先上图。
日历.gif
#define MSS_SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width)
#define MSS_SCREEN_HEIGHT ([UIScreen mainScreen].bounds.size.height)
#define MSS_UTILS_COLORRGB(r,g,b) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1]
#define MSS_Iphone6Scale(x) ((x) * MSS_SCREEN_WIDTH / 375.0f)
#define MSS_ONE_PIXEL (1.0f / [[UIScreen mainScreen] scale])

/*定义属性*/

// 选择点击颜色
#define SelectedColor [UIColor cyanColor]
// 被选中间颜色
#define SelMiddleColor [UIColor greenColor]


// DateLabel默认文字颜色
#define MSS_TextColor [UIColor blackColor]
// DateLabel选中时的背景色
#define MSS_SelectBackgroundColor MSS_UTILS_COLORRGB(29, 154, 72)
// DateLabel选中后文字颜色
#define MSS_SelectTextColor [UIColor whiteColor]
// SubLabel文字颜色
#define MSS_SelectSubLabelTextColor MSS_UTILS_COLORRGB(29, 154, 180);
// SubLabel选中开始文字
#define MSS_SelectBeginText @"开始"
// SubLabel选中结束文字
#define MSS_SelectEndText @"结束"
// 节日颜色
#define MSS_HolidayTextColor [UIColor purpleColor]
// 周末颜色
#define MSS_WeekEndTextColor [UIColor redColor]
// 不可点击文字颜色
#define MSS_TouchUnableTextColor MSS_UTILS_COLORRGB(150, 150, 150)
// 周视图高度
#define MSS_WeekViewHeight 60
// headerView线颜色
#define MSS_HeaderViewLineColor [UIColor lightGrayColor]
// headerView文字颜色
#define MSS_HeaderViewTextColor [UIColor blackColor]
// headerView高度
#define MSS_HeaderViewHeight 50
// 弹出层文字颜色
#define MSS_CalendarPopViewTextColor [UIColor whiteColor]
// 弹出层背景颜色
#define MSS_CalendarPopViewBackgroundColor [UIColor blackColor]

typedef NS_ENUM(NSInteger, MSSCalendarViewControllerType)
{
    MSSCalendarViewControllerLastType = 0,// 只显示当前月之前
    MSSCalendarViewControllerMiddleType,// 前后各显示一半
    MSSCalendarViewControllerNextType// 只显示当前月之后
};

typedef NS_ENUM(NSInteger, MSSCalendarWithUserType)
{
    MSSCalendarHotelType = 0,  // 酒店   入住 --- 离店
    MSSCalendarTrainType,      // 火车票,飞机票,单选无价格
    MSSCalendarAplaceType,     // 基地   价格
    MSSCalendarSecnicType,     // 景点   价格
    MSSCalendarPlaneType,      // 机票
    MSSCalendarActivityType    // 活动,线路

};

可以自定义以上属性,什么颜色,类型什么的。

核心思路就在这块,简单明了,传的有一个参数limitMonth,显示几个月的数据,MSSCalendarViewControllerNextType就是今天以后, components.month -= 1;获取当前月份减一,不要问为什么减一,打隔断点看看就知道了,MSSCalendarViewControllerLastType这是今天以前的limitMonth月的日期。


- (NSArray *)getCalendarDataSoruceWithLimitMonth:(NSInteger)limitMonth type:(MSSCalendarViewControllerType)type
{
    NSMutableArray *resultArray = [[NSMutableArray alloc]init];
    
    NSDateComponents *components = [self dateToComponents:_todayDate];
    components.day = 1;
    if(type == MSSCalendarViewControllerNextType)
    {
        components.month -= 1;
    }
    else if(type == MSSCalendarViewControllerLastType)
    {
        components.month -= limitMonth;
    }
    else
    {
        components.month -= (limitMonth + 1) / 2;
    }
    NSInteger i = 0;
    for(i = 0;i < limitMonth;i++)
    {
        components.month++;
        MSSCalendarHeaderModel *headerItem = [[MSSCalendarHeaderModel alloc]init];
        NSDate *date = [self componentsToDate:components];
        [_dateFormatter setDateFormat: @"yyyy年MM月"];
        NSString *dateString = [_dateFormatter stringFromDate:date];
        headerItem.headerText = dateString;
        headerItem.calendarItemArray = [self getCalendarItemArrayWithDate:date section:i];   // section就是当月数据页面的位置
        [resultArray addObject:headerItem];
    }
    return resultArray;
}

一共limitMonth个月,从第一个月开始排序,整理数组。下面是每一个单独月的日期数据


// 得到每一天的数据源
- (NSArray *)getCalendarItemArrayWithDate:(NSDate *)date section:(NSInteger)section
{
    NSMutableArray *resultArray = [[NSMutableArray alloc]init];
    NSInteger tatalDay = [self numberOfDaysInCurrentMonth:date];  // 本月多少天
    NSInteger firstDay = [self startDayOfWeek:date];  // 本月第一天是周几
     // 0 星期日  1  星期一      6星期六
    
    NSDateComponents *components = [self dateToComponents:date];
    
    // 判断日历有多少列
    // 一共多少天 加 第一天是周几就可以算出本月cell的数量

    NSInteger tempDay = tatalDay + (firstDay - 1);
    NSInteger column = 0;
    if(tempDay % 7 == 0)
    {
        column = tempDay / 7;
    }else{
        column = tempDay / 7 + 1;
    }
    
    NSInteger i = 0;
    NSInteger j = 0;
    components.day = 0;
    for(i = 0;i < column;i++)
    {
        for(j = 0;j < 7;j++)
        {
            if(i == 0 && j < firstDay - 1)  // 本月第一天前的数据
            {
                MSSCalendarModel *calendarItem = [[MSSCalendarModel alloc]init];
                calendarItem.year = 0;
                calendarItem.month = 0;
                calendarItem.day = 0;
                calendarItem.chineseCalendar = @"";
                calendarItem.holiday = @"";
                calendarItem.week = -1;
                calendarItem.dateInterval = -1;
                [resultArray addObject:calendarItem];
                continue;
            }
            components.day += 1;
            if(components.day == tatalDay + 1) // 本月数据循环结束
            {
                i = column;// 结束外层循环
                break;
            }
            MSSCalendarModel *calendarItem = [[MSSCalendarModel alloc]init];
            calendarItem.year = components.year;
            calendarItem.month = components.month;
            calendarItem.day = components.day;
            calendarItem.week = j;
            NSDate *date = [self componentsToDate:components];
            // 时间戳
            calendarItem.dateInterval = [self dateToInterval:date];
            if(_startDate == calendarItem.dateInterval)
            {
                _startIndexPath = [NSIndexPath indexPathForRow:0 inSection:section];
            }
            [self setChineseCalendarAndHolidayWithDate:components date:date calendarItem:calendarItem];
            
            [resultArray addObject:calendarItem];
        }
    }
    return resultArray;
}

价格日历这块,无非就是处理数据的时候加上了priceArray
@[ @{@"date":@"2018-09-08",@"price":@"238"}]


- (NSArray *)getJYCCalendarDataSoruceWithLimitMonth:(NSInteger)limitMonth type:(MSSCalendarViewControllerType)type calendarType:(MSSCalendarWithUserType)calendarType priceArray:(NSArray *_Nonnull)priceArray{
    
    NSMutableArray *resultArray = [[NSMutableArray alloc]init];
    NSMutableArray *priceMuArr = [NSMutableArray arrayWithArray:priceArray];
    
    NSDateComponents *components = [self dateToComponents:_todayDate];
    components.day = 1;
    if(type == MSSCalendarViewControllerNextType)
    {
        components.month -= 1;
    }
    else if(type == MSSCalendarViewControllerLastType)
    {
        components.month -= limitMonth;
    }
    else
    {
        components.month -= (limitMonth + 1) / 2;
    }
    NSInteger i = 0;
    for(i = 0;i < limitMonth;i++)
    {
        components.month++;
        MSSCalendarHeaderModel *headerItem = [[MSSCalendarHeaderModel alloc]init];
        NSDate *date = [self componentsToDate:components];
        [_dateFormatter setDateFormat: @"yyyy年MM月"];
        NSString *dateString = [_dateFormatter stringFromDate:date];
        headerItem.headerText = dateString;
        
        // 价格
        NSString *MMyue = [dateString substringWithRange:NSMakeRange(5, 2)];
        NSMutableArray *priArr = [NSMutableArray array];
        for (NSDictionary *dic in priceMuArr) {  // 从数据中选中当月的数据
            NSString *da = [dic objectForKey:@"date"];
            if (da.length > 7) {
                NSString *mm = [da substringWithRange:NSMakeRange(5, 2)];
                if (MMyue == mm) {
                    [priArr addObject:dic];
                }
            }
        }
        [priceMuArr removeObjectsInArray:priArr];  // 移除选中月份的数据
        
        
        
        headerItem.calendarItemArray = [self getCalendarItemArrayWithDate:date section:i calendarType:calendarType withPriceArray:priArr];
        [resultArray addObject:headerItem];   
        
        if (calendarType == MSSCalendarSecnicType || calendarType == MSSCalendarAplaceType || calendarType == MSSCalendarActivityType) {
            if (priceMuArr.count <= 0) {    // 如果价格数据数组为空时,不在展示以后的日历
                break;
            }
        }
    }
    return resultArray;
}

找到第一天数据的具体时间,然后依次把数组中的数据赋值给第一天后的每一天(必须保证时间日历的连续性)

        NSInteger priceTime = 0;
        if (priceArray.count > 0) {
            NSDictionary *dic = priceArray[0];
            NSString *ti = [dic objectForKey:@"date"];
            if (ti.length > 0) {
                priceTime = [self dateToInterval:[self dateFromString:ti]];
            }
        }

                // 时间戳
                NSInteger dateInterVal = [self dateToInterval:date];
                calendarItem.dateInterval = dateInterVal;
                if (priceTime == dateInterVal) {
                    indexB = 0;
                }
                if (indexB < priceArray.count) {
                    NSDictionary *dic = priceArray[indexB];
                    //                if (calendarType == MSSCalendarSecnicType) {
                    //                    calendarItem.price = [dic objectForKey:@"salePrice"];
                    //                }else if (calendarType == MSSCalendarAplaceType){
                    //                    calendarItem.userPrice = [dic objectForKey:@"userprice"];
                    //                    calendarItem.price = [dic objectForKey:@"webprice"];
                    //                }
                    calendarItem.price = [dic objectForKey:@"price"];
                    calendarItem.userInteractionEnabled = YES;
                }
                indexB++;

基地日历:选择一个开始时间后,后台刷新日历数据,把最小时间以前和最大时间以后的数据全部设置为不可选 userInteractionEnabled = NO;

- (NSArray *)getCalendarDataSoruceWithMinNum:(NSInteger )minNum MaxNum:(NSInteger )maxNum startDate:(NSInteger )startDate endDate:(NSInteger )endDate andDataArray:(NSArray *)dataArray{
    
    NSMutableArray *daArr = [NSMutableArray array];
    [daArr addObjectsFromArray:dataArray];
    if (startDate > 0) {
        for (int i = 0; i < dataArray.count; i++) {
            MSSCalendarHeaderModel *headerItem = daArr[i];
            for (int j = 0; j < headerItem.calendarItemArray.count; j++) {
                
                MSSCalendarModel *model = headerItem.calendarItemArray[j];
                
                if (model.dateInterval == startDate) {
                    
                }
                if(model.dateInterval >= startDate + minNum*24*3600 && model.dateInterval <= startDate + maxNum*24*3600){
                    model.middleSelect = YES;
                    model.userInteractionEnabled = YES;
                    
                }else{
                    model.userInteractionEnabled = NO;
                }
            }
        }
    }

    if (endDate > 0  || startDate == 0) {
        for (int i = 0; i < dataArray.count; i++) {
            MSSCalendarHeaderModel *headerItem = daArr[i];
            for (int j = 0; j < headerItem.calendarItemArray.count; j++) {
                
                MSSCalendarModel *model = headerItem.calendarItemArray[j];
                if ([model.price floatValue] > 0) {
                    model.userInteractionEnabled = YES;
                    model.middleSelect = NO;
                }
            }
        }
    }
    
    return daArr;
    
}

详见代码,
代码参考了一位大神,自己也封装了业务需求。
GitHub项目地址

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 141,232评论 1 296
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 60,610评论 1 254
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 93,049评论 0 210
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 40,691评论 0 171
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 48,375评论 1 250
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 38,571评论 1 169
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 30,262评论 2 266
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,036评论 0 163
  • 想象着我的养父在大火中拼命挣扎,窒息,最后皮肤化为焦炭。我心中就已经是抑制不住地欢快,这就叫做以其人之道,还治其人...
    爱写小说的胖达阅读 28,781评论 6 225
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 32,394评论 0 211
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,154评论 2 212
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 30,470评论 1 222
  • 白月光回国,霸总把我这个替身辞退。还一脸阴沉的警告我。[不要出现在思思面前, 不然我有一百种方法让你生不如死。]我...
    爱写小说的胖达阅读 24,151评论 0 31
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,023评论 2 210
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 31,376评论 3 201
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,579评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 25,926评论 0 163
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 33,342评论 2 227
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 33,466评论 2 229

推荐阅读更多精彩内容

  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    X先生_未知数的X阅读 15,847评论 3 114
  • 告别 文||与你相识 你从自己的意识里离开 没人要你做什么 你从自己的倔强里离开 没有你的世界没人哭泣 谁也不是谁...
    与你相识_40fa阅读 78评论 0 2
  • 1小时后的七夕没有人给你转账,你可以找我 你先把钱转给我,我再转给你,手续费只抽2%,还配合换头像,...
    海盗lucifer阅读 101评论 0 0
  • 体验入:今天公司举办了中秋欢乐会,负责策划的5个人实在是太棒了,内容很精彩,又感动。先生还承诺了大家如果完成业绩奖...
    Tracy_zhang阅读 91评论 0 4