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


当前回答

或者使用SwiftUI GeometryReader api。

struct V: View {
    var body: some View {
        GeometryReader { geometry in
            Text("\(geometry.safeAreaInsets.top)")
            Text("\(geometry.safeAreaInsets.bottom)")
        }
    }
}


代码可能不起作用,但却说明了这个想法。

其他回答

对于iPhone 14设备使用如下。

let app = UIApplication.shared
var statusBarHeight: CGFloat = 0.0
let window = app.windows.filter {$0.isKeyWindow}.first
statusBarHeight = window?.windowScene?.statusBarManager?.statusBarFrame.height ?? 0
let topPadding = window?.safeAreaInsets.top ?? 0.0
statusBarHeight = statusBarHeight >= topPadding ? statusBarHeight:topPadding

这里所有的答案都很有帮助,感谢所有提供帮助的人。

然而,正如我所看到的,安全区域的主题有点混乱,这似乎没有很好的记录。

所以我将在这里总结,尽可能让它容易理解safeAreaInsets, safeAreaLayoutGuide和LayoutGuide。

在ios7中,苹果在UIViewController中引入了topLayoutGuide和bottomLayoutGuide属性, 它们允许你创建约束,以防止你的内容被UIKit栏(如状态栏、导航栏或选项卡栏)隐藏 使用这些布局指南可以指定内容的约束, 避免它被顶部或底部的导航元素(UIKit栏,状态栏,导航或标签栏…)隐藏。

举个例子,如果你想让tableView从顶部屏幕开始你可以这样做

self.tableView.contentInset = UIEdgeInsets(top: -self.topLayoutGuide.length, left: 0, bottom: 0, right: 0)

在iOS 11中,苹果已经弃用了这些属性,取而代之的是单一的安全区域布局指南

苹果说这是安全区域

Safe areas help you place your views within the visible portion of the overall interface. UIKit-defined view controllers may position special views on top of your content. For example, a navigation controller displays a navigation bar on top of the underlying view controller’s content. Even when such views are partially transparent, they still occlude the content that is underneath them. In tvOS, the safe area also includes the screen’s overscan insets, which represent the area covered by the screen’s bezel.

下图为iPhone 8和iPhone x系列突出显示的安全区域:

safeAreaLayoutGuide是UIView的一个属性

获取safeAreaLayoutGuide的高度:

extension UIView {
   var safeAreaHeight: CGFloat {
       if #available(iOS 11, *) {
        return safeAreaLayoutGuide.layoutFrame.size.height
       }
       return bounds.height
  }
}

这将返回图片中箭头的高度。

现在,如何获得顶部“缺口”和底部主屏幕指示器高度?

这里我们将使用safeAreaInsets

视图的安全区域反映了未被导航栏、标签栏、工具栏和其他模糊视图控制器视图的祖先所覆盖的区域。(在tvOS中,安全区域反映的是屏幕边框未覆盖的区域。)通过将此属性中的insets应用于视图的边界矩形,可以获得视图的安全区域。如果视图当前没有安装在视图层次结构中,或者在屏幕上还不可见,则此属性中的边缘嵌入为0。

下面将显示iPhone 8和iPhone x系列的不安全区域及其与边缘的距离。

现在,如果导航栏添加

那么,现在如何求不安全区域高度呢?我们将使用安全区域设置

这里有一些解决方案,但它们在一个重要的事情上有所不同,

第一个:

self.view.safeAreaInsets

这将返回EdgeInsets,你现在可以访问顶部和底部了解insets,

第二个:

UIApplication.shared.windows.first{$0.isKeyWindow }?.safeAreaInsets

第一个你使用的是视图insets,所以如果有一个导航栏,它将被考虑,然而第二个你访问的是窗口的safeAreaInsets,所以导航栏将不会被考虑

对于 SwiftUI:

Code

private struct SafeAreaInsetsKey: EnvironmentKey {
    static var defaultValue: EdgeInsets {
        UIApplication.shared.windows[0].safeAreaInsets.insets
    }
}

extension EnvironmentValues {
    
    var safeAreaInsets: EdgeInsets {
        self[SafeAreaInsetsKey.self]
    }
}

private extension UIEdgeInsets {
    
    var insets: EdgeInsets {
        EdgeInsets(top: top, leading: left, bottom: bottom, trailing: right)
    }
}

使用

struct MyView: View {
    
    @Environment(\.safeAreaInsets) private var safeAreaInsets
    
    var body: some View {
        Text("Ciao")
            .padding(safeAreaInsets)
    }
}

对于iOS 13+/Swift 5,除了这个,没有其他方法适合我:

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

斯威夫特4

if let window = UIApplication.shared.windows.first {
    
    let topPadding = window.safeAreaInsets.top
    let bottomPadding = window.safeAreaInsets.bottom
    
}

从课堂使用

class fitToTopInsetConstraint: NSLayoutConstraint {
    
    override func awakeFromNib() {
        
        if let window = UIApplication.shared.windows.first {
            
            let topPadding = window.safeAreaInsets.top
            
            self.constant += topPadding
            
        }
        
    }
}

class fitToBottomInsetConstraint: NSLayoutConstraint {
    
    override func awakeFromNib() {
        
        if let window = UIApplication.shared.windows.first {
            
            let bottomPadding = window.safeAreaInsets.bottom
            
            self.constant += bottomPadding
            
        }
        
    }
}

在构建应用程序时,您将看到安全区域填充。