iOS安全区

Rosberry的 iOS开发人员Evgeny M.

您还记得,Apple在iOS 7中引入了UIViewController中的topLayoutGuidebottomLayoutGuide属性,以描述屏幕区域未被任何内容(状态栏,导航栏,工具栏,选项卡栏等)覆盖。在iOS 11中,Apple已弃用这些特性并介绍了安全区域。 Apple建议我们不要在安全区域之外放置任何控件,因此在iOS 11中,当您在iOS应用程序中放置视图时必须使用新的安全区域API。

当我们开始在应用程序中支持iPhone X分辨率和安全区域时,我们发现UIKit中的许多类都具有新的安全区域功能。 本文的目的是总结和描述它们。

议程

本文分为以下几部分:

  • UIView
  • UIViewController
  • UIScrollView
  • UITableView
  • UICollectionView

这些都是具有新安全区域的类别 属性和方法

UIView

在iOS 11中,UIViewController的topLayoutGuidebottomLayoutGuide属性已由UIView中的新安全区域属性代替:

safeAreaInsets属性 手段 该屏幕不仅可以覆盖顶部和底部,还可以覆盖所有侧面。 推出iPhone X时,我们很清楚为什么需要左右两侧的插图。

iPhone 8与iPhone X安全区域(纵向)
iPhone 8和iPhone X安全区域(横向)

iPhone X的顶部和底部安全区域以纵向放置。 左,右和下插图为横向。


让我们看一个例子。 两个自定义子视图 带有文本标签和固定高度的控件被添加到视图控制器视图的顶部和底部,并附加到视图的边缘。

子视图将附加到视图的边缘

如您所见,子视图的内容由顶部的凹口和底部的主页指示器重叠。 为了正确放置子视图,我们可以使用手动布局将它们附加到安全区域:

或使用自动布局:

子视图附加到超级视图安全区域

看起来更好。 此外,您可以将子视图内容直接附加到子视图子类☝️中的安全区域插图中:

要么:

子视图将附加到视图的边缘。 标签贴在Superview安全区域。

现在,您不仅可以在视图控制器中而且可以在子视图层次结构中的任何位置将视图附加到安全区域,这很酷。

在iOS 11中,UIViewController具有一个新属性:

当视图控制器子视图覆盖嵌入式子视图控制器视图时使用。 例如,当条为半透明时,Apple在UINavigationController和UITabBarController中使用其他安全区域插图。

半透明导航栏和标签栏的安全区域插图。 子视图将附加到视图的边缘。 标签贴在Superview安全区域。

它很好用,但隐藏状态栏时会发生奇怪的事情😬

半透明导航栏,标签栏和隐藏状态栏的安全区域插图。 子视图将附加到视图的边缘。 标签贴在Superview安全区域。

所有安全区域插图均已正确计算,但导航栏已移至缺口下方的顶部。 据我所知,这是一个非常可悲的错误,除了一些解决方法外,目前没有任何方法可以修复它。

当您更改其他安全区域插图或系统更改了安全区域插图时,将调用UIView和UIViewController中的适当方法

模拟iPhone X安全区域

还可以使用其他安全区域插图来测试您的应用程序如何支持iPhoneX。如果您无法在模拟器上测试应用程序且没有iPhone X It,则该功能非常有用。

模拟iPhone X安全区域插图
模拟iPhone X安全区域插图

让我们向视图控制器添加带有文本标签的滚动视图,并将其附加到视图的边缘。

滚动视图被附加到视图的边缘

如您所见,滚动视图的插图在顶部和底部自动调整。 在iOS 7和更高版本的滚动视图中,可以使用UIViewController的automaticAdjustsScrollViewInsets属性管理内容插入调整行为,但在iOS 11中,它已弃用并由新的UIScrollView的contentInsetAdjustmentBehavior属性代替:

内容插页调整行为

永不-滚动视图 内容插图永远不会调整。 这很简单。

滚动视图将附加到视图的边缘( contentInsetAdjustmentBehavior == .never)。

scrollableAxes —仅针对可滚动轴调整内容插图。 例如,当滚动视图内容大小的高度大于框架大小的高度或启用alwaysBounceVertical属性时,垂直轴可滚动。 类似地,当内容大小宽度大于框架大小宽度或启用alwaysBounceHorizo​​ntal属性时,水平轴可滚动。

滚动视图附加到视图的边缘( contentInsetAdjustmentBehavior == .scrollableAxes)。 垂直轴是可滚动的。

在横向方向上,仅调整底部内容插图。 由于水平轴不可滚动,因此无法调整左右内容插图。

始终-针对所有可滚动轴和不可滚动轴调整滚动视图内容插图

滚动视图将附加到视图的边缘( contentInsetAdjustmentBehavior == .always)。 垂直轴是可滚动的。

自动—默认值和最有趣的值。 当满足以下条件时,它始终总是相同:

  • 滚动视图水平轴可滚动,垂直轴不可滚动
  • 滚动视图是视图控制器视图的第一个子视图
  • 视图控制器是导航或标签栏控制器的子级
  • 自动启用AdjustsScrollViewInsets

在所有其他情况下, 自动 scrollableAxes相同

在UIScrollView类中可以找到有关自动行为的其他描述:

类似于.scrollableAxes,但是为了向后兼容,如果滚动视图由导航控制器内部具有viewAd的视图控制器拥有且具有autoAdjustsScrollViewInsets = YES,则也将调整top&bottom contentInset,无论滚动视图是否可滚动

Apple文档的描述略有不同:

当滚动视图是导航或标签栏控制器当前显示的视图控制器的内容视图时,始终会垂直调整内容。 如果滚动视图可水平滚动,则当存在非零安全区域插图时,也会调整水平内容偏移。

因此,由于向后兼容,默认情况下自动行为是自动的 -具有水平可滚动轴的滚动视图在iOS 10和iOS 11中具有相同的顶部和底部插图。

调整后的内容插图

在iOS 11中,UIScrollView具有新的AdjustedContentInset属性:

contentInsetAdjustedContentInset有什么区别? 当滚动视图被顶部的导航栏和底部的选项卡栏覆盖时,让我们打印两个值:

调整了iOS 10和iOS 11(iPhone 7)的内容插图

现在,如果我们从各个方面向contentInset添加10点, 然后再次打印两个值:

调整了iOS 10和iOS 11(iPhone 7)的内容插图

我们将看到,在iOS 11中,实际的滚动视图内容插图可以从AdjustedContentInset属性读取,而不能从contentInset属性读取。 这意味着,当您的应用程序同时支持iOS 10和iOS 11时,应创建用于调整内容插图的不同逻辑。

如果更改contentInset或系统调整了内容插入,则将调用UIScrollView和UIScrollViewDelegate中的适当方法

让我们将带有自定义标题和自定义单元格的表视图添加到视图控制器,并将其附加到视图的边缘。

表格视图被附加到视图的边缘( insetsContentViewsToSafeArea == true )。 标头和单元格是透明的。 单元格的内容视图具有白色背景。 标头的内容视图具有红色背景。

自定义标题具有添加到标题的内容视图的标签。 自定义单元格具有添加到该单元格的内容视图的标签和一个添加到该单元格的分隔符。 标头和单元格是透明的。 单元格的内容视图具有白色背景。 标头的内容视图具有红色背景。

您可以看到页眉和单元格的内容视图框架在横向方向上已更改。 同时,单元格和分隔符框架未更改。 这是默认行为,可以通过新的UITableView的insetsContentViewsToSafeArea属性进行管理:

如果禁用内容视图插图:

表格视图附加到视图的边缘( insetsContentViewsToSafeArea == false )。 标头和单元格是透明的。 单元格的内容视图具有白色背景。 标头的内容视图具有红色背景。

您将看到现在页眉/页脚/单元格内容视图框架等于页眉/页脚/单元格框架。

所有这一切意味着,在iOS 11中,如果将标题/页脚/单元格子视图的位置添加到内容视图中,则无需更改它们,UITableView将为您完成此工作👍。

让我们尝试在UICollectionView中创建相同的项目列表:

集合视图将附加到视图的边缘。 单元格是透明的,但单元格的内容视图具有白色背景。 标头具有红色背景。

集合视图使用UICollectionViewFlowLayout。 滚动方向是垂直的。 单元格是透明的,但是单元格的内容视图具有白色背景。 标头(又名UICollectionReusableView)没有contentView,本身具有红色背景。

从屏幕快照中可以看到,默认情况下,集合视图不会插入页眉/页脚/单元格内容。 正确布局内容的唯一方法是将页眉/页脚/单元格子视图附加到页眉/页脚/单元格安全区域:

集合视图将附加到视图的边缘。 单元格是透明的,但单元格的内容视图具有白色背景。 标头具有红色背景。 标头/单元格的内容被附加到标头/单元格的安全区域。

现在,让我们更改集合视图的像元大小以形成网格:

集合视图附加到视图的边缘(sectionInsetReference == .fromContentInset)。 使用UICollectionViewFlowLayout。 垂直轴是可滚动的。

如您所见,在横向方向上,单元格被切口重叠。 为了解决这个问题,我们可以将安全区域插图添加到节内容插图中,但是在iOS 11中,UICollectionViewFlowLayout具有一个新的sectionInsetReference属性,可以为您执行此操作:

要产生期望的结果,只需设置fromSafeArea值。 在这种情况下,实际的部分内容插图将等于部分内容插图加上安全区域插图。

集合视图附加到视图的边缘(sectionInsetReference == .fromSafeArea)。 使用UICollectionViewFlowLayout。 垂直轴是可滚动的。

类似地,当使用fromLayoutMargins值时, 会将集合视图布局边距添加到节内容插图中:

集合视图附加到视图的边缘(sectionInsetReference == .fromLayoutMargins)。 使用UICollectionViewFlowLayout。 垂直轴是可滚动的。

苹果在iOS 11中添加了许多有用的工具来与安全区域配合使用。 在本文中,我试图总结并描述它们。 我希望它可以帮助您将应用程序采用到安全区域。 另外,我建议您观看相关的WWDC视频并阅读文章:

  • 为iOS 11更新您的应用
  • 可可触摸的新功能
  • 为iPhone X构建应用程序
  • 相对于安全区域定位内容
  • 为iPhone X设计

使用情节提要的人的特殊链接(我I):

  • 安全区域布局指南
  • Xcode 9的安全区域

您也可以玩我为本文创建的示例。

rosberry / SafeAreaExample
通过在GitHub.github.com上创建一个帐户为SafeAreaExample开发做出贡献

如果您有任何问题,请发表评论。 感谢您的阅读!