iOS根据后台数据自定义日历控件

项目需求,需要一个日历,来展示对应日期对应的课程.

数据返回的大致结构

原理

返回数据解析:
返回数据是按照周日为一周的开始;
将一个月的日期对应星期展示,每一组不够填充的部分使用上一个月或者下一个月的日期填满,以此来达到显示日历对应星期是填满的.(如上图中,灰色部分的日期是上一个月)
最外层数组的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];
      	}
      }
    
至此,根据后台数据创建日历控件就算完成了,当然,日历控件很多种,记录一下,以供学习.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值