项目需求,需要一个日历,来展示对应日期对应的课程.
原理
返回数据解析:
返回数据是按照周日为一周的开始;
将一个月的日期对应星期展示,每一组不够填充的部分使用上一个月或者下一个月的日期填满,以此来达到显示日历对应星期是填满的.(如上图中,灰色部分的日期是上一个月)
最外层数组的count值可能是4|5|6;
内侧数组的count都是7;
步骤
-
1.首先完成一个无限轮播器(相信你已经掌握了这项技能).
-
2.数据处理:数据请求到之后,对数据进行处理并模型转换
- (void)getModelWithDataArr:(NSArray *)Array { //day_status:用来判断该日期是类型 //day_status 0:当天 1:上月日期 2:当月日期 3:下月日期 NSMutableArray *arrayM = [NSMutableArray array]; for (int i = 0; i < Array.count; i++) {//Array:请求到的数组数据 NSArray *tempArray = tempTotalArray[i]; NSMutableArray *temp1 = [NSMutableArray array]; for (int j = 0; j < tempArray.count; j++) { NSDictionary *dict = tempArray[j]; WMCalenderModel *model = [WMCalenderModel modelWithDictionary:dict]; if ([model.day_status integerValue] == 0) {//判断是否是当天并记录当天日期 self.day_time = model.day_time;//day_time:记录当天的属性 model.isSelected = YES;//设置选中状态 } [temp1 addObject:model];//内层数组 } [arrayM addObject:temp1];//外层数组 } self.calenderTotalArray = arrayM.copy;//calenderTotalArray:总的数据模型数组 //数据处理完成后刷新控件 [self updateCircleViewUI]; [self.circleView reloadData]; } - (void)updateCircleViewUI { [self.circleView mas_updateConstraints:^(MASConstraintMaker *make) { make.height.offset(Main_Screen_Width / 7 * self.calenderTotalArray.count); }]; self.layout.itemSize = CGSizeMake(Main_Screen_Width, Main_Screen_Width / 7 * self.calenderTotalArray.count); }
-
3.在轮播图的cell上添加日历控件视图.
使用UICollectionView来实现日期的展示
- (UICollectionView *)calenderView { if (!_calenderView) { UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc]init]; _calenderView = [[UICollectionView alloc]initWithFrame:CGRectZero collectionViewLayout:layout]; ///日期item的大小 layout.itemSize = CGSizeMake(Main_Screen_Width/7, Main_Screen_Width/7); layout.minimumLineSpacing = 0; layout.minimumInteritemSpacing = 0; _calenderView.dataSource = self; _calenderView.delegate = self; [_calenderView registerClass:[WMCalenderCell class] forCellWithReuseIdentifier:calenderViewCellId]; _calenderView.backgroundColor = [UIColor clearColor]; } return _calenderView; } //组数 4/5/6 - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView { return self.calenderTotalArray.count; } //行数 - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return [self.calenderTotalArray[section] count];//每组均为7,可写死(性能好嘛) } - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { WMCalenderCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:calenderViewCellId forIndexPath:indexPath]; WMCalenderModel *model = (WMCalenderModel *)self.calenderTotalArray[indexPath.section][indexPath.row]; cell.model = model; cell.backgroundColor = [UIColor clearColor]; return cell; } /** 模型:WMCalenderModel.h 模型属性 @property (nonatomic, strong) NSString *day_text; @property (nonatomic, strong) NSString *day_status; @property (nonatomic, strong) NSString *is_point; @property (nonatomic, strong) NSString *day_time; @property (nonatomic, assign) BOOL isSelected;//自定义字段,用来判断是否是选中 */
-
4.WMCalenderCell的展示
- (void)setModel:(FXCalenderModel *)model { _model = model; if (model.lessons.count > 0) {//如上图中,日期下面的小圆点表示对应日期有相应的事件,有事件时显示小圆点. self.point.hidden = NO; } else { self.point.hidden = YES; } //day_status 0 当天 1上一月 2当月 3下一月 //因为点击上一月日期或者下一月日期时,会跳转到对应月份显示 //所以此处只判断当天和当月日期需要展示的UI. if ([model.day_status isEqualToString:@"0"] && model.isSelected == YES) {//本月当天,并且此时是选中状态 self.labCell.textColor = WhiteColor; self.point.backgroundColor = WhiteColor; self.viewBg.hidden = NO; } else if ([model.day_status isEqualToString:@"0"] && model.isSelected == NO) {//本月当天,此时是未选中状态 self.labCell.textColor = MasterColor; self.point.backgroundColor = MasterColor; self.viewBg.hidden = YES; } else if ([model.day_status isEqualToString:@"2"] && model.isSelected == YES){//当月非当天,选中 self.labCell.textColor = WhiteColor; self.point.backgroundColor = WhiteColor; self.viewBg.hidden = NO; } else if ([model.day_status isEqualToString:@"2"] && model.isSelected == NO) {//当月非当天,未选中 self.labCell.textColor = WhiteColor; self.point.backgroundColor = MasterColor; self.viewBg.hidden = YES; } self.labCell.text = model.day_text; }
-
5.点击事件的处理.
需求:点击时:
点击当月日期,显示日期背景蓝绿色圆,并相应更改UI(如小圆点的颜色等);
点击上月日期,刷新数据,并选中点击的日期,显示背景蓝绿色圆;
点击下月日期,刷新数据,并选中点击的日期,显示背景蓝绿色圆;
滑动时:
左滑,刷新数据,并选中当前日期对应的日期
右滑,刷新数据,并选中当前日期对应的日期//日期cell的点击事件: - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { FXCalenderModel *model = (FXCalenderModel *)self.calenderTotalArray[indexPath.section][indexPath.row]; //点击到上一月或下一月的日期后跳转到对应月份和点击日期 if ([model.day_status integerValue] == 1 || [model.day_status integerValue] == 3) {//点击上一月还是下一月 if ([_delegate respondsToSelector:@selector(chooseMonthWith:andDay_time:)]) {//代理 [_delegate chooseMonthWith:[model.day_status integerValue] andDay_time:model.day_time]; } } else {//点击的是当月日期 if ([_delegate respondsToSelector:@selector(selectedCellWithDay_time:)]) { [_delegate selectedCellWithDay_time:model.day_time]; } } } //点击当页面中日期是上一月或下一月日期调用方法 - (void)chooseMonthWith:(NSInteger)sender andDay_time:(NSString *)day_time { //sender 是day_status 1 上月 2当月 3下月 self.day_time = day_time;//self.day_time:记录点击的日期 if (sender == 1) {//上一月 [self getClickMonth:-1]; } else if (sender == 3) {//下一月 [self getClickMonth:1]; } } /// MARK: 点击非本月的日期的方法 - (void)getClickMonth:(NSInteger)month {//NSCalendar : gregorian NSDate *newMonth = [self.gregorian dateByAddingUnit:NSCalendarUnitMonth value:month toDate:self.currentMonth options:0]; self.currentMonth = newMonth;//self.currentMonth:记录当前月 //给后台传递的时间戳,返回对应月份的数据 NSTimeInterval time = [self.currentMonth timeIntervalSince1970]; NSString *usrds = [NSString stringWithFormat:@"%@?ts=%f",Course_GET_getCourseScheduleTime,time]; [self loadNextOrPreviousDataWithUrl:usrds andTokens:[CHSettingClass sharedClass].saveCompleteToken]; } //数据加载 数据加载部分根据自己的请求来获取 - (void)loadNextOrPreviousDataWithUrl:(NSString *)url andTokens:(NSString *)tokens { CHNetworkManager *net = [CHNetworkManager sharedManager]; [net requestWithType:GET urlStr:url params:nil withSuccessBlock:^(id responseObject) { [self hideUserInteractionEnabledLoadingView]; NSLog(@"%@",responseObject); if ([[responseObject objectForKey:@"code"]integerValue] == 0) { NSArray *tempTotalArray = [[responseObject objectForKey:@"data"] objectForKey:@"calendar"]; NSMutableArray *arrayM = [NSMutableArray array]; for (NSInteger i = 0; i < tempTotalArray.count; i++) { NSArray *tempArray = tempTotalArray[i]; NSMutableArray *temp1 = [NSMutableArray array]; for (NSInteger j = 0; j < tempArray.count; j++) { NSDictionary *dict = tempArray[j]; WMCalenderModel *model = [WMCalenderModel modelWithDictionary:dict]; if ([self.day_time isEqualToString:tempArr[j].day_time]) { model.isSelected = YES; } [temp1 addObject:model]; } [arrayM addObject:temp1]; } self.calenderTotalArray = arrayM.copy; [self updateCircleViewUI]; [self.circleView reloadData]; } else { [self showAlert:[responseObject objectForKey:@"message"] andDisAppearAfterDelay:2.0]; } }]; } //手动滑动轮播cell,完成时调用 -(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView{ UICollectionView *collectionView = (UICollectionView *)scrollView; if (collectionView == self.circleView) { //获取偏移量 Main_Screen_Width屏幕宽度 self.offsetX = scrollView.contentOffset.x; NSLog(@"%f",self.offsetX/Main_Screen_Width); //self.pageNumber记录的当前轮播图显示的页数 if (self.offsetX / Main_Screen_Width == self.pageNumber) { return; } else if (self.offsetX / Main_Screen_Width < self.pageNumber) { NSDate *previousMonth = [self.gregorian dateByAddingUnit:NSCalendarUnitMonth value:-1 toDate:self.currentMonth options:0]; self.currentMonth = previousMonth; NSLog(@"%@",previousMonth); } else { NSDate *nextMonth = [self.gregorian dateByAddingUnit:NSCalendarUnitMonth value:1 toDate:self.currentMonth options:0]; self.currentMonth = nextMonth; NSLog(@"%@",nextMonth); } NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; [dateFormatter setDateFormat:@"yyyy-MM-dd"]; self.day_time = [dateFormatter stringFromDate:self.currentMonth]; NSTimeInterval time = [self.currentMonth timeIntervalSince1970]; NSString *usrds = [NSString stringWithFormat:@"%@?ts=%f",Course_GET_getCourseScheduleTime,time]; [self showLoadingViewWithMessage:nil andUserInteractionEnabled:YES]; [self loadNextOrPreviousDataWithUrl:usrds andTokens:[CHSettingClass sharedClass].saveCompleteToken]; } }