从 prefersStatusBarHidden 检测屏幕缺口
Posted
技术标签:
【中文标题】从 prefersStatusBarHidden 检测屏幕缺口【英文标题】:Detect screen notch from prefersStatusBarHidden 【发布时间】:2021-05-13 14:33:15 【问题描述】:*** 上有很多关于检测 iPhone 设备屏幕是否有刘海的问题,例如this one。答案几乎总是建议使用顶部窗口的 safeAreaInsets
属性。我已经在我的应用程序中使用它来确定是否应该显示状态栏,来自当前显示的视图控制器的 prefersStatusBarHidden
方法。我想在有缺口时显示状态栏,但在没有缺口时不显示。它在我的所有测试中都运行良好,但对于某些客户来说,状态栏有时会消失,即使他们使用的是带有缺口的设备(iPhone 12 Pro Max)。
我调查了一下,我认为问题可能是由对safeAreaInsets
的递归调用引起的,请参见以下调用堆栈:
这有点道理。为了确定安全区域需要多大,ios 需要知道状态栏是否需要显示。因此,它调用可见视图控制器的prefersStatusBarHidden
,然后使用安全区域来确定......
尽管进行了递归调用,但它在测试中仍然适用于我,但如前所述,它有时对某些用户来说会失败。我需要使用prefersStatusBarHidden
,因为在顶层应用程序包含UITabBarController
,只有一个选项卡隐藏了状态栏。其他选项卡应始终显示状态栏,与是否有缺口无关。
我考虑过使用sysctlbyname
和"hw.machine"
参数检查设备类型,然后使用映射表来获取缺口/无缺口结果。但这有一个缺点,即需要为每个新的 iPhone 型号更新映射表,并且它在模拟器上不起作用,它总是返回 Mac 机器名称。
任何想法如何以更好的方式解决这个问题?我可以简单地避免递归调用,但这会解决问题吗?
我现在确定缺口的代码(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;
【问题讨论】:
【参考方案1】:我不熟悉 Obj-c,但它看起来像是一个计算属性/函数。每次访问它时,它都会插入当前的安全区域并返回一个 Bool。
但问题是您正在根据该布尔值设置prefersStatusBarHidden
。如果状态栏被隐藏,安全区域会变小。然后,下次访问hasTopNotch
属性时,它会返回一个不正确的值。
相反,我所做的是检查安全区域只有一次应用程序启动。您用户的设备永远不会改变,因此您不需要功能。在斯威夫特:
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
【讨论】:
在启动时执行一次可能是个好主意。不过,我需要找到合适的时间来做这件事。由于我不使用情节提要,因此无法在 SceneDelegate 中使用。 @fishinear 可能在 AppDelegate 的didFinishLaunching
?
我试过了。如果我在设置顶层视图控制器之前这样做,那么safeAreaInsets
总是返回 (0,0,0,0)。设置顶层视图控制器的那一刻,iOS 立即调用该视图控制器的prefersStatusBarHidden
,它需要有缺口信息,它需要真正的safeAreaInsets
信息......看起来我被递归调用卡住了,但我认为无论如何最好在启动期间执行一次。以上是关于从 prefersStatusBarHidden 检测屏幕缺口的主要内容,如果未能解决你的问题,请参考以下文章
iOS 13 中的 prefersStatusBarHidden 问题
Swift/iOS 8,当 prefersStatusBarHidden() 设置为 true 时,状态栏不隐藏
在 iOS 7 中,如果我使用 `prefersStatusBarHidden` 方法隐藏状态栏,导航栏会缩小/失去高度。我可以停止这种行为吗?