You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FSCalendar自定义单元格选中时过去未来日期保灰及获取方法

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实例做日期计算,避免时区、时分秒精度导致的判断偏差,两种常用方案:

  1. 标记集合存储(适合固定标记的日期)
    初始化两个集合分别存储过去、未来标记日期的标准化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;
}
  1. 实时计算(适合动态按时间规则标记的日期)
    如果你的标记规则是基于当前时间动态判断(比如早于今日为过去、晚于今日为未来),直接用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 21:39:27