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

Swift中如何实现UICollectionView的水平与垂直双向滚动?

日历事件目录效果

您好。

我正在尝试制作一个日历事件目录,效果如图所示。我希望垂直滚动时切换目录显示的时段,水平滚动时切换日历的日期。目前已实现垂直滚动功能,但不知道如何在Swift中添加水平滚动功能。请问有没有可行的实现方案?

我询问的是Swift中的实现方法,感谢解答。


Swift实现双滚动日历目录方案

在Swift里做这种横竖双滚动的日历组件,我有两种常用的思路,你可以参考:

方案一:嵌套UIScrollView(简单易上手)

这种方式适合日期数量不多的场景,直接用两个滚动视图嵌套就行:

  • 外层用横向UIScrollView,负责切换不同日期的页面,建议开启isPagingEnabled让切换更顺滑
  • 每个日期页面内部,放你已经做好的纵向UIScrollView(也就是时段滚动目录)
  • 关键要给两个ScrollView设置正确的contentSize:
    • 横向ScrollView的contentSize.width = 单页面宽度 × 总日期数
    • 纵向ScrollView的contentSize.height = 你的时段列表总高度

简单代码示例:

// 初始化横向滚动容器
let horizontalScroll = UIScrollView()
horizontalScroll.isPagingEnabled = true
horizontalScroll.showsHorizontalScrollIndicator = false
horizontalScroll.frame = view.bounds
view.addSubview(horizontalScroll)

// 假设要展示7天的日历
for dayIdx in 0..<7 {
    // 复用你已经实现好的纵向滚动视图
    let verticalScroll = YourExistingVerticalScrollView()
    verticalScroll.frame = CGRect(
        x: CGFloat(dayIdx) * view.bounds.width,
        y: 0,
        width: view.bounds.width,
        height: view.bounds.height
    )
    // 给当前日期的视图加载对应事件数据
    verticalScroll.loadEvents(for: getTargetDate(at: dayIdx))
    horizontalScroll.addSubview(verticalScroll)
}

// 设置横向滚动容器的内容尺寸
horizontalScroll.contentSize = CGSize(
    width: view.bounds.width * 7,
    height: view.bounds.height
)

方案二:UICollectionView横向分页+内部纵向列表(高性能)

如果需要展示的日期数量很多,用这种复用Cell的方式性能更好:

  • 外层用UICollectionView,设置布局为横向滚动的UICollectionViewFlowLayout,并开启分页
  • 每个CollectionViewCell内部嵌入你做好的纵向滚动列表(UITableView或UICollectionView)
  • 可以通过collectionView(_:willDisplay:forItemAt:)监听当前显示的日期,实时更新对应的数据

核心代码示例:

// 配置外层横向CollectionView的布局
let flowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = .horizontal
flowLayout.itemSize = view.bounds.size
flowLayout.minimumLineSpacing = 0

let calendarCollection = UICollectionView(
    frame: view.bounds,
    collectionViewLayout: flowLayout
)
calendarCollection.isPagingEnabled = true
calendarCollection.showsHorizontalScrollIndicator = false
calendarCollection.register(CalendarDayCell.self, forCellWithReuseIdentifier: "DayCell")
calendarCollection.dataSource = self
calendarCollection.delegate = self
view.addSubview(calendarCollection)

// 自定义Cell,内部包含纵向滚动列表
class CalendarDayCell: UICollectionViewCell {
    let eventsTable = UITableView()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        // 这里配置你的UITableView,复用你之前实现的纵向滚动逻辑
        eventsTable.frame = bounds
        addSubview(eventsTable)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func setup(with events: [CalendarEvent]) {
        // 更新表格数据
        eventsTable.reloadData()
    }
}

// 实现CollectionView数据源方法
extension YourViewController: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return totalDaysCount // 你的总日期数
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "DayCell", for: indexPath) as! CalendarDayCell
        let events = getEventsForDay(at: indexPath.item)
        cell.setup(with: events)
        return cell
    }
}

两种方案都能满足你的需求,要是日期少就选第一种,快速搞定;日期多的话第二种更省内存~

内容的提问来源于stack exchange,提问作者Seong Min Choo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:38:33