小屏无刘海iOS设备能否调整UICollectionView的y轴位置做适配?
解决方案
你完全可以针对无刘海老旧设备调整y轴位置,以下是两种可行实现方案:
方案1:维持现有frame写法,动态调整y值
你当前固定写死y=162是适配了刘海屏的顶部安全区高度,无刘海设备的顶部安全区比刘海屏少24pt,所以会出现顶部留白过多的问题。你可以通过动态获取设备顶部安全区高度来计算y值,自动适配不同设备:
override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() collectionView?.backgroundColor = appBackgroundColor // 动态获取顶部安全区高度 let topSafeAreaHeight = view.safeAreaInsets.top // 118为你顶部安全区以上的所有控件总高度,可根据实际需求调整 let collectionViewTopOffset = topSafeAreaHeight + 118 // 动态设置frame collectionView?.frame = CGRect( x: 11, y: collectionViewTopOffset, width: self.view.frame.width-20, height: self.view.frame.height - collectionViewTopOffset - 3 ) }
如果需要单独判断设备是否有刘海,也可以用如下扩展:
extension UIDevice { static var hasNotch: Bool { guard #available(iOS 11.0, *) else { return false } return UIApplication.shared.windows.first?.safeAreaInsets.top ?? 0 > 20 } }
使用时直接赋值即可:
let yOffset: CGFloat = UIDevice.hasNotch ? 162 : 138 collectionView?.frame = CGRect(x: 11, y: yOffset, width: self.view.frame.width-20, height: self.view.frame.height - yOffset - 3)
方案2:使用Auto Layout约束适配,解决布局切换异常问题
你之前添加约束后无法切换布局,大概率是两个原因导致的:
- 你在
listLayout和gridLayout的懒加载代码中重复创建UICollectionView实例、重复调用addSubview,导致约束冲突 - 代码中混用了
folderCollectionView和collectionView两个变量,逻辑混乱
你可以按如下方式修改,一次添加约束永久适配所有屏幕,同时支持正常切换布局:
- 先删除
listLayout和gridLayout懒加载中如下两行冗余代码:
// 冗余代码,全部删除 folderCollectionView = UICollectionView(frame: .zero,collectionViewLayout: listLayout) view.addSubview(collectionView!)
- 改造
collectionViewSetUp方法,统一初始化并添加约束:
func collectionViewSetUp() { // 仅初始化一次collectionView collectionView = UICollectionView(frame: .zero,collectionViewLayout: gridLayout) collectionView?.translatesAutoresizingMaskIntoConstraints = false collectionView?.showsVerticalScrollIndicator = false collectionView?.showsHorizontalScrollIndicator = false collectionView?.dataSource = self collectionView?.delegate = self collectionView?.allowsMultipleSelection = true collectionView?.allowsSelection = true collectionView?.isUserInteractionEnabled = true collectionView?.register(collectionViewListLayoutCell.self, forCellWithReuseIdentifier: "collectionViewListLayoutCell") collectionView?.register(collectionViewCell.self, forCellWithReuseIdentifier: "collectionViewCell") view.addSubview(collectionView!) // 仅添加一次约束,自动适配所有设备 NSLayoutConstraint.activate([ collectionView!.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 11), collectionView!.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -9), // 直接对接安全区顶部,自动适配刘海/非刘海屏 collectionView!.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 118), collectionView!.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -3) ]) }
- 布局切换按钮点击事件用系统原生方法切换,不需要修改约束:
@objc func switchLayoutButtonTapped() { let targetLayout = isListView ? gridLayout : listLayout collectionView?.setCollectionViewLayout(targetLayout, animated: true) isListView.toggle() }
- 清空
viewDidLayoutSubviews中的冗余配置,仅保留必要代码:
override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() collectionView?.backgroundColor = appBackgroundColor }
内容的提问来源于stack exchange,提问作者Abhishek Kumar
相关产品推荐
相关产品推荐

