如何在视图加入层级前获取iOS横竖屏安全区域Insets及无安全区最大显示尺寸?
解决iOS横竖屏非当前模式下的安全区域及可用尺寸问题
核心思路
利用UIWindowScene的特征集合能力,模拟目标横竖屏模式的traitCollection,直接获取对应模式下的安全区域边距,再结合屏幕尺寸计算不含安全区域的最大可用空间。
代码实现
import UIKit /// 获取指定横竖屏模式下的安全区域边距 /// - Parameter orientation: 目标方向(竖屏/横屏) /// - Returns: 对应模式的安全区域Insets func getSafeAreaInsets(for orientation: UIInterfaceOrientation) -> UIEdgeInsets { guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else { return .zero } // 根据目标方向构建对应的TraitCollection let verticalSizeClass: UIUserInterfaceSizeClass = orientation.isPortrait ? .regular : .compact let horizontalSizeClass: UIUserInterfaceSizeClass = orientation.isPortrait ? .compact : .regular let targetTrait = UITraitCollection(verticalSizeClass: verticalSizeClass, horizontalSizeClass: horizontalSizeClass) return windowScene.safeAreaInsets(for: targetTrait) } /// 计算指定横竖屏模式下不含安全区域的最大显示尺寸 /// - Parameter orientation: 目标方向(竖屏/横屏) /// - Returns: 对应模式的最大可用尺寸 func getMaxAvailableSize(for orientation: UIInterfaceOrientation) -> CGSize { let screenBounds = UIScreen.main.bounds let insets = getSafeAreaInsets(for: orientation) // 根据方向适配宽高计算逻辑 let availableWidth: CGFloat let availableHeight: CGFloat if orientation.isPortrait { availableWidth = screenBounds.width - insets.left - insets.right availableHeight = screenBounds.height - insets.top - insets.bottom } else { // 横屏时屏幕bounds的宽高会交换,需对应调整 availableWidth = screenBounds.height - insets.left - insets.right availableHeight = screenBounds.width - insets.top - insets.bottom } return CGSize(width: availableWidth, height: availableHeight) } // 使用示例 let portraitAvailableSize = getMaxAvailableSize(for: .portrait) let landscapeAvailableSize = getMaxAvailableSize(for: .landscapeLeft)
注意事项
- 该方法仅适用于iOS 13+,依赖
UIWindowScene获取场景上下文; - 横屏的
landscapeLeft和landscapeRight模式下安全区域边距一致,无需分别计算; - 无安全区域的老设备(如iPhone 8及以前)会返回屏幕全尺寸,符合预期;
- iPad的横竖屏尺寸类逻辑不同,但该方法仍能正确获取对应模式的安全区域。
内容的提问来源于stack exchange,提问作者Khal
相关产品推荐
相关产品推荐

