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

如何在选中的UICollectionView单元格上显示计数标签?

iOS 月历组件预选中时段+右上角序号标签实现方案

整个实现不需要改动现有CalendarCollectionView的核心滚动、月切换逻辑,只需要补充数据映射、单元格自定义、渲染逻辑三个模块即可:

  • 预选中日期预处理
    不要在列表滚动渲染时重复做排序、匹配计算,提前把预选中的PreselectedPeriod数据处理好:

    1. 写一个日期归一化方法,把所有日期的时分秒清零,避免同一天因为时间戳精度、时分秒差异导致匹配失败
    2. 把所有预选中日期按自然天升序排列
    3. 生成[Date: Int]类型的键值对,key是归一化后的日期,value是对应要显示的序号(从1开始计数)
      参考代码:
    let defaultCalendar = Calendar.current
    // 日期归一化:只保留年月日维度
    func stripTime(from date: Date) -> Date {
        let comps = defaultCalendar.dateComponents([.year, .month, .day], from: date)
        return defaultCalendar.date(from: comps)!
    }
    
    // 提前生成索引映射
    let sortedSelectedDates = preselectedPeriod.sorted()
    var date2IndexMap = [Date: Int]()
    for (offset, date) in sortedSelectedDates.enumerated() {
        date2IndexMap[stripTime(from: date)] = offset + 1
    }
    
  • 自定义日期单元格
    在你现有日期单元格的基础上新增两个UI元素即可:

    1. 选中背景视图:放在单元格内容视图最底层,左右撑满、上下留合适边距,用来实现连续选中的连片效果,注意相邻cell的选中背景不要留左右边距,不然会出现拼接缝隙
    2. 右上角序号标签:UILabel控件,放在选中背景视图上方、日期数字的右上角,字号比日期数字小2-3号,做圆角处理,默认隐藏,用自动布局钉在单元格右上角,留2-3pt的边距即可,文字色和选中背景做足够的对比度。
  • 集合视图渲染逻辑
    在collectionView(_:cellForItemAt:)数据源方法里,拿到当前cell对应的日期后做匹配渲染:

    1. 先把当前cell的日期做同样的归一化处理
    2. 查date2IndexMap中是否存在当前日期的key:
      • 不存在:走普通未选中逻辑,隐藏选中背景、隐藏序号标签,设置普通日期文字色
      • 存在:取出对应序号,显示选中背景、显示序号标签并赋值对应数字,同时根据当前日期在排序后选中数组里的位置,给选中背景设置不同的圆角,实现连续选中两端圆角、中间无圆角的效果:
        • 选中时段只有1天:四个角全加圆角
        • 是选中时段的第一天:只加左上下两个角的圆角
        • 是选中时段的最后一天:只加右上下两个角的圆角
        • 是选中时段的中间日期:不加圆角,和相邻cell的选中背景自然拼接
          参考代码:
    let currentCellDate = stripTime(from: cellModel.date)
    if let orderNum = date2IndexMap[currentCellDate] {
        cell.showSelectedState = true
        cell.orderLabel.isHidden = false
        cell.orderLabel.text = "\(orderNum)"
        // 处理圆角逻辑
        let isFirstDay = orderNum == 1
        let isLastDay = orderNum == sortedSelectedDates.count
        if sortedSelectedDates.count == 1 {
            cell.selectedBgView.layer.cornerRadius = 8
            cell.selectedBgView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMaxXMaxYCorner]
        } else if isFirstDay {
            cell.selectedBgView.layer.cornerRadius = 8
            cell.selectedBgView.layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner]
        } else if isLastDay {
            cell.selectedBgView.layer.cornerRadius = 8
            cell.selectedBgView.layer.maskedCorners = [.layerMaxXMinYCorner, .layerMaxXMaxYCorner]
        } else {
            cell.selectedBgView.layer.cornerRadius = 0
        }
    } else {
        cell.showSelectedState = false
        cell.orderLabel.isHidden = true
        cell.selectedBgView.layer.cornerRadius = 0
    }
    

踩坑提示:如果你的日历支持跨月展示预选中时段,只需要在每次切换月份触发collectionView刷新前,确保当前月的所有日期都做了归一化匹配即可,不需要额外写跨月判断逻辑。

效果参考示意图

内容的提问来源于stack exchange,提问作者Abhishek Kumar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 04:03:25