最合适的方法是什么来获得不安全区域的顶部和底部高度?


当前回答

试试这个:

在Objective C中

if (@available(iOS 11.0, *)) {
    UIWindow *window = UIApplication.sharedApplication.windows.firstObject;
    CGFloat topPadding = window.safeAreaInsets.top;
    CGFloat bottomPadding = window.safeAreaInsets.bottom;
}

在斯威夫特

if #available(iOS 11.0, *) {
    let window = UIApplication.shared.keyWindow
    let topPadding = window?.safeAreaInsets.top
    let bottomPadding = window?.safeAreaInsets.bottom
}

在Swift - iOS 13.0及以上

//使用windows数组中的第一个元素,KeyWindow已弃用

if #available(iOS 13.0, *) {
    let window = UIApplication.shared.windows.first
    let topPadding = window.safeAreaInsets.top
    let bottomPadding = window.safeAreaInsets.bottom
}

其他回答

对于那些切换到横向模式的人,你必须确保在旋转后使用viewSafeAreaInsetsDidChange来获得最新的值:

private var safeAreaInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)

override func viewSafeAreaInsetsDidChange() {
        if #available(iOS 11.0, *) {
            safeAreaInsets = UIApplication.shared.keyWindow!.safeAreaInsets
        }
}

我正在使用CocoaPods框架和UIApplication。shared不可用,然后我在视图窗口中使用safeAreaInsets:

if #available(iOS 11.0, *) {
    let insets = view.window?.safeAreaInsets
    let top = insets.top
    let bottom = insets.bottom
}
extension UIViewController {
    var topbarHeight: CGFloat {
        return
            (view.window?.safeAreaInsets.top ?? 0) +
            (view.window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0.0) +
            (self.navigationController?.navigationBar.frame.height ?? 0.0)
    }
}

safeAreaLayoutGuide 当视图在屏幕上可见时,该指南反映了未被导航栏、选项卡栏、工具栏和其他祖先视图覆盖的视图部分。(在tvOS中,安全区域反映未覆盖屏幕边框的区域。)如果视图当前没有安装在视图层次结构中,或者在屏幕上还不可见,布局指南边等于视图的边。

然后在截图中获得红色箭头的高度:

self.safeAreaLayoutGuide.layoutFrame.size.height

这里有一个基于其他答案的免费函数,当你的rootController从任何地方布局时,它都应该是可调用的。你可以把它当做一个独立的函数。

    func safeAreaInsets() -> UIEdgeInsets? {
    (UIApplication
        .shared
        .keyWindow?
        .rootViewController)
        .flatMap {
            if #available(iOS 11.0, *) {
                return $0.view.safeAreaInsets
            } else {
                return .init(
                    top: $0.topLayoutGuide.length,
                    left: .zero,
                    bottom: $0.bottomLayoutGuide.length,
                    right: .zero
                )
            }
        }
}