Xcode 9的安全区域

在探索 Xcode9测试版时,在接口构建器上发现了 安全区。我很好奇,试图了解苹果的安全区域文档,大意是说 “与自动布局直接交互的视图区域”,但它并没有让我满意,我想知道这个新东西的实际用途。

有人知道吗?

enter image description here

结论段落来自苹果文档的安全区域。

UILayoutGuide 类旨在执行以前由虚拟视图执行的所有任务,但是要以更安全、更有效的方式执行。布局指南不定义新视图。它们不参与视图层次结构。相反,它们只是在自己的视图坐标系中定义一个矩形区域,这个区域可以与 Auto Layout 交互。

144938 次浏览

安全区是一个布局指南(安全区布局指南)
表示视图中不被条形图和其他内容遮挡的部分的布局指南。在 iOS11 + 操作系统中,苹果不再使用顶部和底部的布局指南,而代之以单一的安全区域布局指南。

当视图在屏幕上可见时,本指南反映视图中其他内容未覆盖的部分。视图的安全区域反映了导航栏、选项卡栏、工具栏和其他遮挡视图控制器视图的上级所覆盖的区域。(在 tvOS 中,安全区域包含屏幕的边框,这是由 UIScreen 的 overscanCompensationInsets属性定义的。)它还涵盖视图控制器的 additionalSafeAreaInsets属性定义的任何其他空间。如果视图当前未安装在视图层次结构中,或者在屏幕上尚不可见,则布局指南始终与视图的边缘匹配。

对于视图控制器的根视图,此属性中的安全区域表示视图控制器内容中被隐藏的整个部分,以及您指定的任何其他插入。对于视图层次结构中的其他视图,安全区域只反映该视图中模糊的部分。例如,如果视图完全位于其视图控制器的根视图的安全区域内,则此属性中的边缘插入为0。

根据苹果公司的说法,Xcode 9-Release note
Interface Builder 使用 uiView.safeArea/LayoutGuide 来替代 uiViewController 中已经废弃的顶部和底部布局指南。若要使用新的安全区域,请在视图控制器的“文件检查器”中选择“安全区域布局指南”,然后在内容和新的安全区域锚之间添加约束。这样可以防止您的内容被顶部和底部的条形图以及 tvOS 上的过度扫描区域遮挡。当部署到早期版本的 iOS 时,对安全区域的约束会转换为 Top 和 Bottom。

enter image description here


这里是一个简单的参考作为一个比较(使类似的视觉效果)之间的现有(顶部和底部)布局指南和安全区域布局指南。

安全范围布局: enter image description here

自动版式

enter image description here


如何使用安全区域布局?

按照以下步骤寻找解决方案:

  • 启用“安全区域布局”,如果没有启用。
  • 删除’所有约束’,如果他们显示连接与 超级景观和重新连接所有与安全布局锚。或双击约束并编辑从“超级视图”到“安全区域”锚的连接

下面是示例快照,说明如何启用安全区域布局和编辑约束。

enter image description here

以下是上述变化的结果

enter image description here


基于安全区域的布局设计
在为 iPhone X 设计时,你必须确保布局填满屏幕,不被设备的圆角、传感器外壳或访问主屏幕的指示器所遮挡。

enter image description here

大多数使用标准的、系统提供的 UI 元素(如导航栏、表格和集合)的应用程序会自动适应设备的新形式因素。背景材料延伸到显示器的边缘,UI 元素适当地插入和定位。

enter image description here

对于自定义布局的应用程序,支持 iPhone X 也应该相对容易,特别是如果你的应用程序使用自动布局,并坚持安全区域和边缘布局指南。

enter image description here


下面是示例代码(参考自: 安全区布局指南) :
如果在代码中创建约束,请使用 UIView 的 safeAreaLayoutGuide 属性获取相关的布局锚。让我们在代码中重新创建上面的 Interface Builder 示例,看看效果如何:

假设我们在视图控制器中将绿色视图作为一个属性:

private let greenView = UIView()

我们可能有一个函数来设置 viewDidLoad 调用的视图和约束:

private func setupView() {
greenView.translatesAutoresizingMaskIntoConstraints = false
greenView.backgroundColor = .green
view.addSubview(greenView)
}

像往常一样使用根视图的 layoutMarginsGuide 创建前面和后面的边距约束:

 let margins = view.layoutMarginsGuide
NSLayoutConstraint.activate([
greenView.leadingAnchor.constraint(equalTo: margins.leadingAnchor),
greenView.trailingAnchor.constraint(equalTo: margins.trailingAnchor)
])

现在,除非你的目标是 iOS 11,否则你只需要将安全区域布局指南约束用 # 可用包裹起来,然后返回到早期 iOS 版本的顶部和底部布局指南:

if #available(iOS 11, *) {
let guide = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
greenView.topAnchor.constraintEqualToSystemSpacingBelow(guide.topAnchor, multiplier: 1.0),
guide.bottomAnchor.constraintEqualToSystemSpacingBelow(greenView.bottomAnchor, multiplier: 1.0)
])


} else {
let standardSpacing: CGFloat = 8.0
NSLayoutConstraint.activate([
greenView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor, constant: standardSpacing),
bottomLayoutGuide.topAnchor.constraint(equalTo: greenView.bottomAnchor, constant: standardSpacing)
])
}


结果:

enter image description here


按照 UIView扩展,使您以编程方式使用 SafeAreaLayout 变得容易。

extension UIView {


// Top Anchor
var safeAreaTopAnchor: NSLayoutYAxisAnchor {
if #available(iOS 11.0, *) {
return self.safeAreaLayoutGuide.topAnchor
} else {
return self.topAnchor
}
}


// Bottom Anchor
var safeAreaBottomAnchor: NSLayoutYAxisAnchor {
if #available(iOS 11.0, *) {
return self.safeAreaLayoutGuide.bottomAnchor
} else {
return self.bottomAnchor
}
}


// Left Anchor
var safeAreaLeftAnchor: NSLayoutXAxisAnchor {
if #available(iOS 11.0, *) {
return self.safeAreaLayoutGuide.leftAnchor
} else {
return self.leftAnchor
}
}


// Right Anchor
var safeAreaRightAnchor: NSLayoutXAxisAnchor {
if #available(iOS 11.0, *) {
return self.safeAreaLayoutGuide.rightAnchor
} else {
return self.rightAnchor
}
}


}

以下是 目标 C中的示例代码:


以下是 安全区布局指南的苹果开发者官方文档


需要安全区域来处理 iPhone-X 的用户界面设计。以下是如何使用安全区域布局为 iPhone-X 设计用户界面的基本指南

苹果早在 iOS7系统中就引入了 topLayoutGuide 和 bottomLayoutGuide 作为 UIViewController 的属性。它们允许您创建约束,以防止您的内容被 UIKit 条(如状态、导航或选项卡条)隐藏。这些布局指南在 iOS11中已不再使用,取而代之的是单一的安全区布局指南。

有关详细信息,请参阅 链接

安全区域布局指南有助于避免系统 UI 元素的重叠 当定位内容和控件时。

安全区域是介于系统 UI 元素之间的区域,这些元素包括状态栏、导航栏和工具栏或选项卡栏。因此,当您添加一个状态栏到您的应用程序,安全区域收缩。当你添加一个导航栏到你的应用程序,安全区域再次缩小。

在 iPhone X 上,安全区域提供了从屏幕顶部和底部边缘开始的附加插图,即使没有显示条形图。在景观方面,安全区是从屏幕和家庭指示器的侧面插入的。

这是从苹果的视频 为 iPhone X 设计,他们也可视化如何不同的元素影响安全区。

我想提到的是,当我试图改编一个基于 SpriteKit 的应用程序,以避免新 iPhone X 的圆边和“凹槽”时,我第一次意识到了这一点,正如最新的 人机界面指南所建议的那样: UIView的新属性 safeAreaLayoutGuide需要被查询 之后视图已被添加到层次结构(例如,在 -viewDidAppear:上) ,以报告一个有意义的布局框架(否则,它只返回全屏幕大小)。

根据房产文件:

表示视图的 不被酒吧和其他内容所遮蔽。 当视图在屏幕 上可见时,本指南将反映视图中未被导航栏、选项卡栏、, 工具栏和其他祖先视图(在 tvOS 中,安全区域反映 该区域没有覆盖屏幕的边框。) 如果视图不是 当前安装在视图层次结构中,或者尚不可见 在屏幕上,布局指南边缘等于视图 的边缘。

(强调我的)

如果你早在 -viewDidLoad:读它,指南的 layoutFrame将是 \{\{0, 0}, {375, 812}}而不是预期的 \{\{0, 44}, {375, 734}}

enter image description here

  • 早期的 iOS 7.0-11.0 < 反对 > UIKit使用 TopLayoutGuide & 页面设计指南,这是 UIView的属性
  • IOS11 + 使用 SafeArea 布局指南,这也是 UIView的属性

  • 从文件检查器启用 安全区布局指南复选框。

  • 安全区域帮助您将视图放置在整个界面的可见部分内。

  • TVOS中,安全区域还包括屏幕的超扫描插图,它表示屏幕边框覆盖的区域。

  • SafeAreaLayoutGuide 反映了视图中没有被导航栏、选项卡栏、工具栏和其他祖先视图覆盖的部分。
  • 使用安全区域作为布局内容的辅助,如 UIButton 等等

  • 在为 iPhone X 设计时,你必须确保布局填满屏幕,不被设备的圆角、传感器外壳或访问主屏幕的指示器所遮挡。

  • 确保背景延伸到显示器的边缘,垂直滚动布局,如表格和集合,一直延伸到底部。

  • IPhone X 上的状态栏比其他 iPhone 上的状态栏更高。如果您的应用程序假定一个固定的状态栏高度,定位内容低于状态栏,您必须更新您的应用程序,以动态定位内容的基础上,用户的设备。请注意,当语音记录和位置跟踪等后台任务处于活动状态时,iPhone X 上的状态栏不会改变高度 print(UIApplication.shared.statusBarFrame.height)//44 for iPhone X, 20 for other iPhones

  • 家庭指示器容器高度为34点。

  • 一旦你启用了 安全区布局指南,你就可以看到安全区域约束属性列在 Interface Builder 中。

enter image description here

您可以将各个 self.view.safeAreaLayoutGuide的约束设置为-

目的:

  self.demoView.translatesAutoresizingMaskIntoConstraints = NO;
UILayoutGuide * guide = self.view.safeAreaLayoutGuide;
[self.demoView.leadingAnchor constraintEqualToAnchor:guide.leadingAnchor].active = YES;
[self.demoView.trailingAnchor constraintEqualToAnchor:guide.trailingAnchor].active = YES;
[self.demoView.topAnchor constraintEqualToAnchor:guide.topAnchor].active = YES;
[self.demoView.bottomAnchor constraintEqualToAnchor:guide.bottomAnchor].active = YES;

斯威夫特:

   demoView.translatesAutoresizingMaskIntoConstraints = false
if #available(iOS 11.0, *) {
let guide = self.view.safeAreaLayoutGuide
demoView.trailingAnchor.constraint(equalTo: guide.trailingAnchor).isActive = true
demoView.leadingAnchor.constraint(equalTo: guide.leadingAnchor).isActive = true
demoView.bottomAnchor.constraint(equalTo: guide.bottomAnchor).isActive = true
demoView.topAnchor.constraint(equalTo: guide.topAnchor).isActive = true
} else {
NSLayoutConstraint(item: demoView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: demoView, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: demoView, attribute: .bottom, relatedBy: .equal, toItem: view, attribute: .bottom, multiplier: 1.0, constant: 0).isActive = true
NSLayoutConstraint(item: demoView, attribute: .top, relatedBy: .equal, toItem: view, attribute: .top, multiplier: 1.0, constant: 0).isActive = true
}

enter image description here

enter image description here

enter image description here