SwiftUI纯原生方案检测iOS设备顶部刘海及安全区域内边距
纯SwiftUI原生方案判断iOS设备顶部刘海
可以通过SwiftUI原生的GeometryReader获取视图安全区域内边距,无需依赖UIKit组件实现刘海判断,核心逻辑是:非刘海设备顶部安全区域内边距为标准状态栏高度(20pt),刘海设备的顶部内边距会大于该值。
实现方式
方式一:全局复用(通过环境变量)
先定义用于传递安全区域的环境键和偏好键:
// 环境键,用于全局获取安全区域内边距 private struct SafeAreaInsetsKey: EnvironmentKey { static var defaultValue: EdgeInsets = EdgeInsets() } extension EnvironmentValues { var safeAreaInsets: EdgeInsets { get { self[SafeAreaInsetsKey.self] } set { self[SafeAreaInsetsKey.self] = newValue } } } // 偏好键,用于从GeometryReader传递安全区域数据 private struct SafeAreaInsetsPreferenceKey: PreferenceKey { static var defaultValue: EdgeInsets = EdgeInsets() static func reduce(value: inout EdgeInsets, nextValue: () -> EdgeInsets) { value = nextValue() } }
在根视图中注入安全区域信息,并实现判断逻辑:
struct RootView: View { @Environment(\.safeAreaInsets) private var safeAreaInsets private let standardTopInset: CGFloat = 20 // 非刘海设备状态栏高度 var body: some View { VStack { Text(hasTopNotch ? "设备存在顶部刘海" : "设备无顶部刘海") .font(.title) } .frame(maxWidth: .infinity, maxHeight: .infinity) // 通过GeometryReader获取安全区域并传递给环境 .background( GeometryReader { proxy in Color.clear .preference(key: SafeAreaInsetsPreferenceKey.self, value: proxy.safeAreaInsets) } ) .onPreferenceChange(SafeAreaInsetsPreferenceKey.self) { insets in safeAreaInsets = insets } } private var hasTopNotch: Bool { safeAreaInsets.top > standardTopInset } }
方式二:单视图简化版
如果仅在单个视图中使用,可直接通过GeometryReader读取并判断:
struct ContentView: View { private let standardTopInset: CGFloat = 20 var body: some View { GeometryReader { proxy in Text(proxy.safeAreaInsets.top > standardTopInset ? "存在顶部刘海" : "无顶部刘海") .font(.title) .frame(maxWidth: .infinity, maxHeight: .infinity) } } }
关键说明
- 该方案完全基于SwiftUI原生API,未引入任何UIKit代码。
- 阈值
20pt是iOS非刘海设备的标准状态栏高度,刘海设备的顶部安全区域包含状态栏+刘海高度,因此内边距会大于20pt(如iPhone X及以上机型为44pt)。 - 逻辑适配所有iOS设备,包括带刘海的iPad Pro(顶部内边距为44pt)。
内容的提问来源于stack exchange,提问作者Deepak Sharma
相关产品推荐
相关产品推荐

