UICollectionView横向滚动时如何正确设置referenceSizeForHeaderInSection?
嘿,我看了你的代码和问题描述,很快就找到问题所在啦!核心是你搞混了横向滚动时UICollectionViewFlowLayout对Header尺寸的处理逻辑,另外还要明确你到底想要哪种Header布局——是整个CollectionView顶部的通栏Header,还是每个Section左侧的Header?我分两种情况给你解决办法:
一、如果你想要的是「整个CollectionView顶部的通栏Header(和垂直滚动时一样)」
横向滚动时,Section Header默认会跑到Section的左侧,而不是顶部。如果你想保留垂直滚动时那种顶部通栏的Header,就别用Section Header了,改用CollectionView的tableHeaderView:
- 先删掉Section Header相关的代理方法:
viewForSupplementaryElementOfKind和referenceSizeForHeaderInSection - 在初始化方法里添加顶部Header:
override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) { let layout = UICollectionViewFlowLayout() layout.scrollDirection = .horizontal super.init(frame: frame, collectionViewLayout: layout) // 创建顶部Header视图 let headerView = HeaderForCollectionView(frame: CGRect(x: 0, y: 0, width: frame.width, height: 30)) headerView.labelHeader.text = "Hongbei" self.tableHeaderView = headerView // 调整内边距,让单元格在Header下方显示 self.contentInset = UIEdgeInsets(top: 30, left: 20, bottom: 0, right: 0) }
这样设置后,Header会固定在CollectionView顶部,单元格在下方横向滚动,和垂直滚动时的视觉效果一致。
二、如果你想要的是「每个Section左侧的Header」
你现在的问题是把Header的宽度设成了CollectionView的宽度,导致Header占据了整个可见区域,单元格被挤到了Header右侧(超出屏幕),所以一开始看不到。只需要调整Header的宽度为合适的固定值就行:
修改referenceSizeForHeaderInSection方法:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize{ print("referenceSizeForHeaderInSection") // 横向滚动时,这个方法返回的width是Header的水平宽度,height会被系统忽略 // 把width改成你需要的固定值,比如100 return CGSize(width: 100, height: 30) }
另外,你设置的insetForSectionAt里left是20,这个会让Header向右偏移20个点,如果不需要这个偏移,可以把left设为0。
补充说明:横向滚动时FlowLayout的尺寸逻辑
为啥会出现这个问题?因为FlowLayout在不同滚动方向下,对尺寸参数的处理是不一样的:
- 垂直滚动时:Section Header的宽度自动匹配Section宽度,高度用你设置的referenceSize的height值,width会被忽略
- 横向滚动时:Section Header的高度自动匹配Section高度,宽度用你设置的referenceSize的width值,height会被忽略
你之前把Header的width设成CollectionView的宽度,等于让Header占满了整个屏幕的水平空间,单元格自然被挤到外面去啦~
内容的提问来源于stack exchange,提问作者Pruthvi Hariharan

