最合适的方法是什么来获得不安全区域的顶部和底部高度?
当前回答
这里有一个基于其他答案的免费函数,当你的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
)
}
}
}
其他回答
更全面的方法
import SnapKit
let containerView = UIView()
containerView.backgroundColor = .red
self.view.addSubview(containerView)
containerView.snp.remakeConstraints { (make) -> Void in
make.width.top.equalToSuperView()
make.top.equalTo(self.view.safeArea.top)
make.bottom.equalTo(self.view.safeArea.bottom)
}
extension UIView {
var safeArea: ConstraintBasicAttributesDSL {
if #available(iOS 11.0, *) {
return self.safeAreaLayoutGuide.snp
}
return self.snp
}
var isIphoneX: Bool {
if #available(iOS 11.0, *) {
if topSafeAreaInset > CGFloat(0) {
return true
} else {
return false
}
} else {
return false
}
}
var topSafeAreaInset: CGFloat {
let window = UIApplication.shared.keyWindow
var topPadding: CGFloat = 0
if #available(iOS 11.0, *) {
topPadding = window?.safeAreaInsets.top ?? 0
}
return topPadding
}
var bottomSafeAreaInset: CGFloat {
let window = UIApplication.shared.keyWindow
var bottomPadding: CGFloat = 0
if #available(iOS 11.0, *) {
bottomPadding = window?.safeAreaInsets.bottom ?? 0
}
return bottomPadding
}
}
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
CGFloat fBottomPadding = window.safeAreaInsets.bottom;
这适用于整个视图生命周期,在Swift中是一个简单的两行解决方案:
let top = UIApplication.shared.windows[0].safeAreaInsets.top
let bottom = UIApplication.shared.windows[0].safeAreaInsets.bottom
我个人需要它在viewDidLoad和view中。safeAreaInsets还没有计算。
Swift 4,5
使用约束将视图固定到安全区域锚点可以在视图控制器生命周期的任何地方完成,因为它们由API排队,并在视图加载到内存后进行处理。然而,获取安全区值需要等待视图控制器生命周期的结束,如viewDidLayoutSubviews()。
这将插入到任何视图控制器:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let topSafeArea: CGFloat
let bottomSafeArea: CGFloat
if #available(iOS 11.0, *) {
topSafeArea = view.safeAreaInsets.top
bottomSafeArea = view.safeAreaInsets.bottom
} else {
topSafeArea = topLayoutGuide.length
bottomSafeArea = bottomLayoutGuide.length
}
// safe area values are now available to use
}
我更喜欢这种方法,而不是将它从窗口中删除(如果可能的话),因为这是API的设计方式,更重要的是,在所有视图更改期间,值都会更新,比如设备方向更改。
然而,一些自定义呈现的视图控制器不能使用上述方法(我怀疑是因为它们在瞬态容器视图中)。在这种情况下,你可以从根视图控制器获取值,它总是在当前视图控制器生命周期的任何地方可用。
anyLifecycleMethod()
guard let root = UIApplication.shared.keyWindow?.rootViewController else {
return
}
let topSafeArea: CGFloat
let bottomSafeArea: CGFloat
if #available(iOS 11.0, *) {
topSafeArea = root.view.safeAreaInsets.top
bottomSafeArea = root.view.safeAreaInsets.bottom
} else {
topSafeArea = root.topLayoutGuide.length
bottomSafeArea = root.bottomLayoutGuide.length
}
// safe area values are now available to use
}
这里所有的答案都很有帮助,感谢所有提供帮助的人。
然而,正如我所看到的,安全区域的主题有点混乱,这似乎没有很好的记录。
所以我将在这里总结,尽可能让它容易理解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,所以导航栏将不会被考虑
推荐文章
- 禁用所呈现视图控制器的交互式撤销
- 在Swift中转换字符串为日期
- 点击按钮时如何打开手机设置?
- 如何使用UIVisualEffectView来模糊图像?
- 如何修复UITableView分隔符在iOS 7?
- 故事板中的自定义单元格行高设置没有响应
- 如何改变时间和时区在iPhone模拟器?
- 在Swift中使用自定义消息抛出错误/异常的最简单方法?
- 编译器错误:带有Objective-C选择器的方法与前面带有相同Objective-C选择器的声明冲突
- 如何在Swift中获得唯一的设备ID ?
- 如何在Swift中获得枚举值的名称?
- 我如何知道何时UITableView完成了ReloadData?
- 复制文本到剪贴板与iOS
- 在Swift中根据字符串计算UILabel的大小
- 如何调用手势点击在UIView编程在迅速