FSCalendar自定义单元格选中时过去未来日期保灰及获取方法
问题1:选中状态下过去/未来日期文字保持灰色实现
FSCalendar默认会在单元格选中时强制将标题文字改为全局配置的选中色,覆盖自定义的灰色样式,两种可直接落地的方案:
- 代理方式(推荐,耦合度低)
控制器遵守FSCalendarDelegateAppearance协议,实现按日期返回颜色的方法,对需要保持灰色的过去/未来日期,选中态也返回灰色,不会被全局样式覆盖:
// 先统一判断日期是否属于需要置灰的过去/未来日期,替换为你自己的标记逻辑即可 - (BOOL)isGrayDate:(NSDate *)date { NSCalendar *cal = self.calendar.calendar; NSDate *todayStart = [cal startOfDayForDate:[NSDate date]]; NSDate *todayEnd = [cal dateByAddingUnit:NSCalendarUnitDay value:1 toDate:todayStart options:0]; return [date compare:todayStart] == NSOrderedAscending || [date compare:todayEnd] == NSOrderedDescending; } // 默认状态文字颜色 - (UIColor *)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance titleDefaultColorForDate:(NSDate *)date { return [self isGrayDate:date] ? UIColor.lightGrayColor : appearance.titleDefaultColor; } // 选中状态文字颜色,核心是不对置灰日期返回默认选中白色 - (UIColor *)calendar:(FSCalendar *)calendar appearance:(FSCalendarAppearance *)appearance titleSelectionColorForDate:(NSDate *)date { return [self isGrayDate:date] ? UIColor.lightGrayColor : appearance.titleSelectionColor; }
- 自定义cell重写方式(适合cell独立封装场景)
在你继承自FSCalendarCell的自定义单元格类中,重写选中状态方法,在父类逻辑执行完成后修正置灰日期的文字颜色:
- (void)setSelected:(BOOL)selected { [super setSelected:selected]; if (selected && (self.isPastMarkedDate || self.isFutureMarkedDate)) { self.titleLabel.textColor = UIColor.lightGrayColor; } }
注意:不要直接修改FSCalendarAppearance的全局titleSelectionColor属性,会导致所有日期选中后文字颜色都被修改。
问题2:获取自行标记的过去/未来日期方法
核心是和FSCalendar使用同一个NSCalendar实例做日期计算,避免时区、时分秒精度导致的判断偏差,两种常用方案:
- 标记集合存储(适合固定标记的日期)
初始化两个集合分别存储过去、未来标记日期的标准化key,用yyyyMMdd格式的字符串作为key规避时分秒干扰,需要获取时直接从集合取即可:
// 初始化存储属性 @property (nonatomic, strong) NSMutableSet<NSString *> *markedPastDateKeys; @property (nonatomic, strong) NSMutableSet<NSString *> *markedFutureDateKeys; @property (nonatomic, strong) NSDateFormatter *keyFormatter; // 初始化时配置 self.keyFormatter = [[NSDateFormatter alloc] init]; self.keyFormatter.dateFormat = @"yyyyMMdd"; self.markedPastDateKeys = [NSMutableSet set]; self.markedFutureDateKeys = [NSMutableSet set]; // 标记日期时存入 NSDate *targetDate = xxx; NSString *key = [self.keyFormatter stringFromDate:targetDate]; [self.markedPastDateKeys addObject:key]; // 获取/判断时 - (NSArray<NSDate *> *)getAllMarkedPastDates { NSMutableArray *res = [NSMutableArray array]; for (NSString *key in self.markedPastDateKeys) { [res addObject:[self.keyFormatter dateFromString:key]]; } return res.copy; }
- 实时计算(适合动态按时间规则标记的日期)
如果你的标记规则是基于当前时间动态判断(比如早于今日为过去、晚于今日为未来),直接用FSCalendar的历法对象对齐到日维度后遍历判断:
- (void)fetchMarkedDatesWithPastBlock:(void(^)(NSArray<NSDate *> *pastDates))pastBlock futureBlock:(void(^)(NSArray<NSDate *> *futureDates))futureBlock { NSCalendar *cal = self.calendar.calendar; NSDate *todayStart = [cal startOfDayForDate:[NSDate date]]; NSDate *todayEnd = [cal dateByAddingUnit:NSCalendarUnitDay value:1 toDate:todayStart options:0]; NSMutableArray *pastRes = [NSMutableArray array]; NSMutableArray *futureRes = [NSMutableArray array]; // 遍历你加载到日历的所有数据源日期 for (NSDate *date in self.calendarDataSource) { if ([date compare:todayStart] == NSOrderedAscending) { [pastRes addObject:date]; } else if ([date compare:todayEnd] == NSOrderedDescending) { [futureRes addObject:date]; } } pastBlock(pastRes.copy); futureBlock(futureRes.copy); }
提示:不要直接用时间戳比较两个日期,会因时分秒、时区的差异出现判断错误,必须先将日期对齐到当日0点后再比较。
内容的提问来源于stack exchange,提问作者satriani
相关产品推荐
相关产品推荐

