iPhone X上Swift 4集合视图头尾视图全屏适配问题咨询
针对你在Swift 4中遇到的UICollectionView头部无法延伸到刘海顶部、尾部无法到屏幕底部的问题,我整理了以下具体的代码实现方案,适配iPhone X及以上带安全区域的设备:
一、调整UICollectionView的布局约束
首先要确保你的UICollectionView是直接贴到父视图的边缘,而不是约束到安全区域(safeAreaLayoutGuide)。这样才能让Header/Footer有空间延伸到屏幕的最顶部和底部:
// 假设你已经创建了collectionView实例 collectionView.translatesAutoresizingMaskIntoConstraints = false // 绑定到父视图的四个边缘,而非安全区域 NSLayoutConstraint.activate([ collectionView.topAnchor.constraint(equalTo: view.topAnchor), collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor), collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor), collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor) ])
二、关闭系统自动调整内边距
iOS 11及以上系统会自动给UICollectionView添加内边距来避开安全区域,我们需要禁用这个行为,让内容可以铺满整个collectionView:
if #available(iOS 11.0, *) { collectionView.contentInsetAdjustmentBehavior = .never }
三、配置Header视图延伸至顶部
1. 设置FlowLayout的Header尺寸
如果你使用的是UICollectionViewFlowLayout,直接设置Header的参考尺寸即可。Header会从collectionView的顶部(也就是屏幕最顶部)开始布局:
let flowLayout = UICollectionViewFlowLayout() // 假设你的Header需要150pt的高度,包含刘海区域 flowLayout.headerReferenceSize = CGSize(width: view.bounds.width, height: 150) collectionView.collectionViewLayout = flowLayout
2. 自定义HeaderView的内容适配
如果Header里的内容需要避开刘海(比如文字、按钮),在自定义的UICollectionReusableView子类中,把内容约束到自身的safeAreaLayoutGuide,但背景视图要铺满整个Header:
class CustomHeaderView: UICollectionReusableView { override init(frame: CGRect) { super.init(frame: frame) // 背景视图铺满整个Header let bgView = UIView() bgView.backgroundColor = .blue bgView.translatesAutoresizingMaskIntoConstraints = false addSubview(bgView) NSLayoutConstraint.activate([ bgView.topAnchor.constraint(equalTo: topAnchor), bgView.leadingAnchor.constraint(equalTo: leadingAnchor), bgView.trailingAnchor.constraint(equalTo: trailingAnchor), bgView.bottomAnchor.constraint(equalTo: bottomAnchor) ]) // 内容视图约束到安全区域,避开刘海 let titleLabel = UILabel() titleLabel.text = "Header Title" titleLabel.translatesAutoresizingMaskIntoConstraints = false addSubview(titleLabel) NSLayoutConstraint.activate([ titleLabel.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor), titleLabel.centerXAnchor.constraint(equalTo: centerXAnchor) ]) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } }
四、配置Footer视图延伸至屏幕底部
1. 计算底部安全区域高度
先获取设备底部的安全区域高度(iPhone X及以上为34pt,旧设备为0),然后把这个高度加到Footer的基础高度上:
var bottomSafeAreaHeight: CGFloat = 0 if #available(iOS 11.0, *) { bottomSafeAreaHeight = view.safeAreaInsets.bottom } // 设置Footer尺寸,基础高度50pt + 底部安全区域高度 flowLayout.footerReferenceSize = CGSize(width: view.bounds.width, height: 50 + bottomSafeAreaHeight)
2. 自定义FooterView的内容适配
和Header类似,让背景铺满整个Footer,而内容约束到安全区域,避免被Home键条遮挡:
class CustomFooterView: UICollectionReusableView { override init(frame: CGRect) { super.init(frame: frame) // 背景视图铺满整个Footer let bgView = UIView() bgView.backgroundColor = .green bgView.translatesAutoresizingMaskIntoConstraints = false addSubview(bgView) NSLayoutConstraint.activate([ bgView.topAnchor.constraint(equalTo: topAnchor), bgView.leadingAnchor.constraint(equalTo: leadingAnchor), bgView.trailingAnchor.constraint(equalTo: trailingAnchor), bgView.bottomAnchor.constraint(equalTo: bottomAnchor) ]) // 内容视图约束到安全区域,避开底部Home键条 let footerLabel = UILabel() footerLabel.text = "Footer Content" footerLabel.translatesAutoresizingMaskIntoConstraints = false addSubview(footerLabel) NSLayoutConstraint.activate([ footerLabel.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor), footerLabel.centerXAnchor.constraint(equalTo: centerXAnchor) ]) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } }
五、注册Header和Footer
最后别忘了在ViewController里注册你的自定义Header和Footer:
collectionView.register(CustomHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HeaderID") collectionView.register(CustomFooterView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "FooterID")
并且实现collectionView(_:viewForSupplementaryElementOfKind:at:)方法:
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { if kind == UICollectionView.elementKindSectionHeader { let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "HeaderID", for: indexPath) as! CustomHeaderView return header } else { let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "FooterID", for: indexPath) as! CustomFooterView return footer } }
这样设置后,你的Header就会延伸到屏幕最顶部(包括刘海区域),Footer会延伸到屏幕实际底部(包括Home键条区域),同时内容会自动避开安全区域,不会被遮挡。
内容的提问来源于stack exchange,提问作者Mauricio Takashi Kiyama

