Swift开发:恢复状态栏并解决视图超出安全区域问题
解决UICollectionView Cell高度减去iOS状态栏高度的问题
Hey Sam,我看了你遇到的问题——想让UICollectionView的Cell高度等于当前View的高度减去状态栏高度,但之前的几种写法要么编译不通过,要么是硬编码的固定值不够灵活。下面给你一套适配iOS 13+的正确解决方案:
为什么你之前的写法行不通?
- 第一种写法
view.frame.height - [UIApplication sharedApplication].statusBarFrame.size.height是Objective-C的语法,你用的是Swift,自然没法运行; - 直接写
20或20.0f属于硬编码,iOS设备的状态栏高度并不固定:非刘海屏是20pt,刘海屏(iPhone X及以后)是44pt,横屏时还会变化,而且Swift里不需要加f后缀,硬编码的方式完全没法适配不同设备。
正确的实现步骤
1. 适配iOS 13+的状态栏高度获取方法
因为你的项目用了SceneDelegate,iOS 13之后通过UIApplication.shared.statusBarFrame获取状态栏高度的方式已经不太可靠了,推荐从UIWindowScene中获取:
在你的HomeController里添加一个获取状态栏高度的方法:
private func getStatusBarHeight() -> CGFloat { var statusBarHeight: CGFloat = 0 // 从当前活跃的WindowScene中获取状态栏管理器 if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene { statusBarHeight = windowScene.statusBarManager?.statusBarFrame.height ?? 0 } return statusBarHeight }
2. 修改UICollectionView的Cell尺寸计算方法
在你的sizeForItemAt代理方法里调用上面的方法,计算正确的Cell高度:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let statusBarHeight = getStatusBarHeight() // 这里用view.bounds.height比frame更可靠,因为bounds是View自身的尺寸,不受父View影响 let cellHeight = view.bounds.height - statusBarHeight return CGSize(width: view.bounds.width, height: cellHeight) }
额外小提示
如果你的HomeController没有导航栏,也可以用view.safeAreaInsets.top来替代状态栏高度——因为此时safeArea的顶部内边距刚好等于状态栏的高度,代码会更简洁:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let cellHeight = view.bounds.height - view.safeAreaInsets.top return CGSize(width: view.bounds.width, height: cellHeight) }
这样修改后,不管是哪种设备,Cell的高度都会自动适配减去状态栏的高度,完全符合你的需求啦!
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

