使用UIKit Compositional Layout的UICollectionView如何按section滚动或获取偏移量
实现方案核心逻辑
基于Compositional Layout配置了正交滚动(即section内部横向滚动)的UICollectionView,系统会自动为每个设置了orthogonalScrollingBehavior的section生成一个私有的内嵌UIScrollView实例,该section的所有横向滚动逻辑都由这个scrollView管理,你需要的两个功能都可以通过操作这个内嵌scrollView实现。
第一步:获取指定section对应的内嵌滚动视图
给UICollectionView写扩展方法,兼容iOS14+:
extension UICollectionView { /// 获取指定section的内嵌正交滚动视图 /// - Parameter section: 目标section索引 /// - Returns: 对应section的内嵌UIScrollView,未开启正交滚动则返回nil func orthogonalScrollView(for section: Int) -> UIScrollView? { // 先校验section合法性 guard section < numberOfSections, // 取该section的布局属性确定位置范围 let sectionFrame = layoutAttributesForSupplementaryElement(ofKind: UICollectionView.elementKindSectionHeader, at: IndexPath(item: 0, section: section))?.frame ?? layoutAttributesForItem(at: IndexPath(item: 0, section: section))?.frame else { return nil } // 遍历子视图匹配对应位置的内嵌scrollView for subview in subviews where subview is UIScrollView { let scrollView = subview as! UIScrollView if scrollView.frame.minX == sectionFrame.minX, scrollView.frame.minY >= sectionFrame.minY, scrollView.frame.maxY <= sectionFrame.maxY { return scrollView } } return nil } }
注意:该方法依赖的系统内嵌视图结构从iOS13发布Compositional Layout以来到最新iOS17都没有变动,兼容性稳定。
第二步:实现需求功能
继续在刚才的UICollectionView扩展中添加对应方法:
1. 控制指定section滚动到目标偏移
func setContentOffset(_ offset: CGFloat, inSection section: Int, animated: Bool = false) { guard let scrollView = orthogonalScrollView(for: section) else { return } // 横向滚动仅修改x值即可,y保持默认0 scrollView.setContentOffset(CGPoint(x: offset, y: 0), animated: animated) }
调用示例:collectionView.setContentOffset(100, inSection: 2)完全符合你要的调用效果。
2. 获取指定section的contentOffset
func contentOffset(for section: Int) -> CGPoint? { return orthogonalScrollView(for: section)?.contentOffset }
如果仅需要横向偏移,直接取返回值的x属性即可。
注意事项
- 不要对获取到的内嵌scrollView做修改delegate、添加自定义手势等额外操作,仅用来调整偏移、读取滚动状态即可,避免触发系统内部异常
- 如果你的section有固定header,优先用header的布局属性做frame匹配,准确率会更高
- 如果后续系统版本升级修改了内嵌视图结构,只需要调整frame匹配的逻辑即可
内容的提问来源于stack exchange,提问作者darksider
相关产品推荐
相关产品推荐

