从 prefersStatusBarHidden 检测屏幕缺口
Detect screen notch from prefersStatusBarHidden
Whosebug 上有很多关于检测 iPhone 设备是否在屏幕上有凹口的问题,例如 。答案几乎都是推荐使用topwindow的safeAreaInsets
属性。我已经在我的应用程序中使用它来确定是否应该显示状态栏,来自当前显示的视图控制器的 prefersStatusBarHidden
方法。我想在有缺口时显示状态栏,但在没有缺口时不显示。它在我的所有测试中都运行良好,但对于某些客户来说,状态栏有时会消失,即使他们使用的是带缺口的设备(iPhone 12 Pro Max)。
我调查了一下,我认为问题可能是由对 safeAreaInsets
的递归调用引起的,请参见以下调用堆栈:
有点道理。为了确定安全区域需要多大,iOS 需要知道是否需要显示状态栏。因此,它调用可见视图控制器的 prefersStatusBarHidden
,然后使用安全区域确定....
尽管递归调用,它在测试中仍然对我有效,但如前所述,它有时对某些用户失败。我需要使用 prefersStatusBarHidden
,因为在顶层应用程序包含 UITabBarController
,只有一个选项卡隐藏状态栏。其他选项卡应始终显示状态栏,与是否有缺口无关。
我考虑过使用 sysctlbyname
和 "hw.machine"
参数检查设备类型,然后使用映射 table 获得 notch/no-notch 结果。但这有一个缺点,即映射 table 需要为每个新的 iPhone 模型更新,并且它在模拟器上不起作用,模拟器总是 returns [=44] =] 机器名.
有什么更好的解决方法吗?我可以简单地避免递归调用,但这会解决问题吗?
我现在确定缺口的代码(Objective-C):
- (bool) hasTopNotch
{
if (@available(iOS 11.0, *)) {
UIWindow *window = [UIApplication sharedApplication].delegate.window;
UIEdgeInsets insets = window.safeAreaInsets;
return insets.top >= 44;
} else {
return NO;
}
}
我不熟悉 Obj-c,但它看起来像一个计算 property/function。每次访问它,它都会得到当前安全区域的inset和return一个Bool.
但问题是您随后根据该 Bool 设置 prefersStatusBarHidden
。如果隐藏状态栏,安全区域会变小。然后,下次您访问 hasTopNotch
属性 时,它将 return 一个不正确的值。
相反,我所做的是检查安全区域一次且仅一次 应用程序启动。您用户的设备永远不会改变,因此您不需要功能。在 Swift:
var deviceHasNotch = false /// outside any class
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
deviceHasNotch = window?.safeAreaInsets.bottom ?? 0 > 0 /// set it here
}
}
Whosebug 上有很多关于检测 iPhone 设备是否在屏幕上有凹口的问题,例如 safeAreaInsets
属性。我已经在我的应用程序中使用它来确定是否应该显示状态栏,来自当前显示的视图控制器的 prefersStatusBarHidden
方法。我想在有缺口时显示状态栏,但在没有缺口时不显示。它在我的所有测试中都运行良好,但对于某些客户来说,状态栏有时会消失,即使他们使用的是带缺口的设备(iPhone 12 Pro Max)。
我调查了一下,我认为问题可能是由对 safeAreaInsets
的递归调用引起的,请参见以下调用堆栈:
有点道理。为了确定安全区域需要多大,iOS 需要知道是否需要显示状态栏。因此,它调用可见视图控制器的 prefersStatusBarHidden
,然后使用安全区域确定....
尽管递归调用,它在测试中仍然对我有效,但如前所述,它有时对某些用户失败。我需要使用 prefersStatusBarHidden
,因为在顶层应用程序包含 UITabBarController
,只有一个选项卡隐藏状态栏。其他选项卡应始终显示状态栏,与是否有缺口无关。
我考虑过使用 sysctlbyname
和 "hw.machine"
参数检查设备类型,然后使用映射 table 获得 notch/no-notch 结果。但这有一个缺点,即映射 table 需要为每个新的 iPhone 模型更新,并且它在模拟器上不起作用,模拟器总是 returns [=44] =] 机器名.
有什么更好的解决方法吗?我可以简单地避免递归调用,但这会解决问题吗?
我现在确定缺口的代码(Objective-C):
- (bool) hasTopNotch
{
if (@available(iOS 11.0, *)) {
UIWindow *window = [UIApplication sharedApplication].delegate.window;
UIEdgeInsets insets = window.safeAreaInsets;
return insets.top >= 44;
} else {
return NO;
}
}
我不熟悉 Obj-c,但它看起来像一个计算 property/function。每次访问它,它都会得到当前安全区域的inset和return一个Bool.
但问题是您随后根据该 Bool 设置 prefersStatusBarHidden
。如果隐藏状态栏,安全区域会变小。然后,下次您访问 hasTopNotch
属性 时,它将 return 一个不正确的值。
相反,我所做的是检查安全区域一次且仅一次 应用程序启动。您用户的设备永远不会改变,因此您不需要功能。在 Swift:
var deviceHasNotch = false /// outside any class
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
deviceHasNotch = window?.safeAreaInsets.bottom ?? 0 > 0 /// set it here
}
}