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

基于UICollectionView实现同步横向滚动的会议室分时预约组件方案咨询

这种会议室预约的时间轴需求我之前做过类似的,UITableView嵌套UICollectionView确实会踩滚动不同步的坑,给你一个更简洁靠谱的方案,用「外层横向滚动视图 + 单个垂直布局UICollectionView」的组合就能完美解决所有需求:

一、核心布局思路(解决滚动同步问题)

放弃嵌套方案,改用以下结构:

  • 外层容器:一个UIScrollView,只允许横向滚动,负责带动整个时间轴区域同步滚动。
  • 左侧静态标签区:一个垂直排列的UIStackView,固定在scrollView左侧,放置「Room 1」「Room 2」这些房间标签,不随滚动移动。
  • 右侧时间轴内容区:一个UICollectionView,设置为垂直滚动(禁用横向滚动),每个section对应一行:
    • 第0个section:顶部的时间标签行,显示「00:00」「00:15」等时段文本。
    • 第1~N个section:每个section对应一个房间,每行的单元格是15分钟的可预约时段块。

这样外层scrollView横向滚动时,整个CollectionView会同步移动,所有房间行和顶部时间行的滚动完全对齐,彻底解决嵌套导致的独立滚动问题。

二、UICollectionView详细配置

1. 数据源处理

首先计算总时段数:24小时共96个15分钟块(24*60/15=96),所以每个section固定有96个item。

  • numberOfSections(in:) 返回「房间数 + 1」(加1是顶部时间行)。
  • collectionView(_:numberOfItemsInSection:) 直接返回96。
  • collectionView(_:cellForItemAt:) 根据section区分:
    • 第0个section:返回时间标签单元格,显示对应索引的时间文本(比如index 0对应00:00,index 1对应00:15,以此类推)。
    • 其他section:返回可选中的时段单元格,默认背景透明,选中时切换为预约色。

2. 布局实现(推荐iOS 13+用Compositional Layout)

Compositional Layout比FlowLayout更灵活,能轻松实现垂直section+横向item的布局:

func createTimeAxisLayout() -> UICollectionViewLayout {
    // 单个时段单元格的大小:宽度固定40pt,高度占满行高
    let itemSize = NSCollectionLayoutSize(
        widthDimension: .absolute(40),
        heightDimension: .fractionalHeight(1)
    )
    let item = NSCollectionLayoutItem(layoutSize: itemSize)
    
    // 每行的group:水平排列,行高固定60pt,宽度覆盖96个时段的总宽度
    let groupSize = NSCollectionLayoutSize(
        widthDimension: .absolute(CGFloat(96)*40),
        heightDimension: .absolute(60)
    )
    let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
    
    // 每个section就是一行,间距设为0
    let section = NSCollectionLayoutSection(group: group)
    section.interGroupSpacing = 0
    
    return UICollectionViewCompositionalLayout(section: section)
}

如果要兼容iOS 12,用UICollectionViewFlowLayout也可以:设置scrollDirection = .vertical,itemSize = CGSize(width:40, height:60),然后手动计算CollectionView的contentWidth为96*40即可。

三、拖拽选择与预约冲突处理

1. 拖拽选中实现

给CollectionView添加长按拖拽手势,跟踪用户的触摸路径:

  • 记录起始的indexPath,拖拽过程中实时计算当前触摸点对应的indexPath,更新选中的时段范围。
  • 可以在UICollectionViewCell里重写isSelected属性,自动切换背景色,简化状态管理。

2. 同一时段唯一预约逻辑

维护一个字典来记录已选中的时段:比如var bookedSlots: [Int: Int] = [:],key是时段索引(095),value是对应的房间section索引(1N)。

  • 当用户选中某个时段时,先检查bookedSlots中是否已有该时段的记录:
    • 如果有,且不是当前房间,就禁用选中(或者提示该时段已被占用)。
    • 如果没有,就把当前房间的section索引存入字典,同时刷新该时段所有房间的单元格,更新选中状态。
  • 在collectionView(_:cellForItemAt:)中,根据bookedSlots判断:如果当前时段被其他房间占用,就把单元格设为不可交互的灰色;如果被当前房间占用,就设为预约色。

四、优化小技巧

  • 滚动对齐:实现UIScrollViewDelegate的scrollViewWillEndDragging(_:withVelocity:targetContentOffset:)方法,让滚动结束时自动对齐到时段单元格的边界,提升用户体验。
  • 性能优化:确保单元格复用逻辑正确,避免因96*N个单元格导致的卡顿;时间标签单元格可以复用,不需要为每个时段创建新的单元格。
  • 拖拽反馈:拖拽过程中实时更新单元格的背景色,给用户直观的选中反馈,避免操作困惑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:09:57