WWDC 2018:快速将开发项目适配全部的iOS设备

Session 235: UIKit: Apps for Every Size and Shapegit

做者简介:@Hale 丁香园 iOS 工程师github

现现在苹果的移动设备已经不像初代的时候只有一种分辨率尺寸。iOS12 支持包括 iPhone5s、iPhone八、iPhone8 Plus、iPhone X、iPad 等各类尺寸的设备。相信必定有许多开发者对多设备的适配开发有过困扰,本 Session 对快速适配全部型号 iOS 移动设备的开发方法进行了介绍。下面介绍的属性和方法可让开发者用最短的时间让开发项目适配苹果全系列移动设备,同时还保证了用户体验不会受到影响。swift

Safe area and layout margins(安全区域和布局边距)

安全区域

Safe Area在 iOS11 中被提出,它是一个很是重要的属性。相信大多数开发者对这个属性已经并不陌生,Safe Area 的提出主要是为了适配像 iPhone X 同样的全面屏。咱们能够经过 UIViewsafeAreaInsetssafeAreaLayoutGuide 属性来肯定安全区域,同时安全区域限制了视图的可见部分,如 图1 所示。安全

图1

安全区域具备传递性

经过下面两张图咱们能够知道,最底部视图A的安全区域如 图2 所示,随后在上添加一个不受限于视图A安全区域的浅灰色视图B,而后在视图B上添加子视图C,并设置视图C的约束依赖于视图B的 safeAreaLayoutGuide,视图C的可视范围会被限制在 图3 黄色区域,咱们能够得出父视图的安全区域会向上传递,如 图二、3 所示。bash

图2

图3

可扩展安全区域

UIViewController 支持使用 additionalSafeAreaInsets 属性,自定义扩展安全区域大小,以知足一些应用场景。此外 UIView 提供了 safeAreaInsetsDidChange() 方法,UIViewController 提供了 viewSafeAreaInsetsDidChange() 方法,用于检测安全区域的改变。当视图的安全区域发生改变,对应的方法就会被调用,如 图4 所示。markdown

图4

布局边距

iOS8 中提出了 layoutMargins 的概念,其主要用于设置子视图与父视图之间的边距,在 iOS11 中新增了 directionalLayoutMargins,主要为了 Right To Left(RTL)语言下能够进行自动适配。默认状况下,layoutMargin 到各边的距离是8个点。经过在 Interface Builder 里面勾选 Constrain to margins 它会根据版本在 iOS11 及以上的系统中自动使用 directionalLayoutMargins,如 图五、6 所示。app

图5

图6

安全区域和布局边距协同做用

正常状况下子视图的布局边距会依赖父视图的安全区域,可是当设置了insetsLayoutMarginsFromSafeArea = false 以后,子视图能够达到突破父视图安全区域的布局效果,如 图七、8 所示。iphone

图7

图8

布局之子视图传播

当一个视图的preservesSuperviewLayoutMargins属性为 true 时,在对它的子视图进行布局时,父视图的 margin 也会被考虑在内。若是存在一个子视图的 frame 恰好和父视图的 margin 表示区域有重合,此时设置 preservesSuperviewLayoutMargins 为 true ,则子视图会被恰好限制在父视图的 margin 内,如 图九、10 所示。ide

图9

图10

最小边距

UIViewController 存在属性 systemMinimumLayoutMargins,能够对其进行重写,默认状况下 view 的布局边距会受这个属性的返回值制约。以下重写了该属性,则 view 的边距最小会为 [20,20,20,20]。oop

override var systemMinimumLayoutMargins: NSDirectionalEdgeInsets {
        return NSDirectionalEdgeInsets(top: 20, leading: 20, bottom: 20, trailing: 20)
}
复制代码

若设置 viewRespectsSystemMinimumLayoutMargins 为 false,则 view 布局边距不受 systemMinimumLayoutMargins 属性的影响,默认为 [8,8,8,8]。

Scroll views

adjustedContentInset

iOS11 中提出了 UIScrollView 的新属性 adjustedContentInset,它的值等于 UIScrollView 原有的 contentInset 加上 安全区域等 system inset,如 图11 所示。

adjustedContentInset = contentInset + system inset
复制代码

图11

废弃 Automatic Content Inset

本 Session 再次提到 iOS11 以后废除了原有的 UIViewController 属性 automaticallyAdjustsScrollViewInsets 取而代之的是 UIScrollView 的新增枚举 ContentInsetAdjustmentBehavior,该枚举结构以下:

public enum ContentInsetAdjustmentBehavior : Int {
        case automatic
        case scrollableAxes
        case never
        case always
    }
复制代码

以下图若是设置枚举值为 .always ,则默认状况下 scrollViewadjustedContentInset 就等于 safeAreaInsets,便可视区域不会被 navigationBartabBar 遮挡,如 图12 所示。

图12

若是将枚举值设置为 .scrollableAxes,则在能够滚动的方向上,或者设置了 alwaysBounceHorizontal/Vertical 为 true 的时候,Inset 才会生效。如 图14,页面内容比较少的时候,垂直方向上 scrollView 不可滚动,致使文本标题部分被 navigationBar 遮挡,如 图1三、14 所示。

图13

图14

系统默认设置的枚举值是 .automatic, 这个枚举值基本和 .scrollableAxes 表现一致,但惟一不一样的是它还秉承了原来 automaticallyAdjustsScrollViewInsets = true 的特性,在有 navigationBarisTranslucent 为 true 时,即便垂直方向上不可以滚动,依然可以调整 Inset 使内容可见,如 图15 所示。

图15

若是将枚举值设置为 .nerver,则 scrollView 的 Inset 不会受 safeAreaInserts 的影响而改变、如 图16 所示。

图16

编写自适应的应用程序

隐藏 status bar

若果在一些场景下须要隐藏 status bar,咱们通常会这么作:

class ArticleViewController: UIViewController { 
	override var prefersStatusBarHidden: Bool { 
		return true 
	} 
} 
复制代码

不幸的是在 iPhone X 上面这么写是无效的,在 iPhone X 上面只有在隐藏了 navigationBar 的前提下,上面这段代码才会生效,因此苹果官方给出的建议是同时隐藏 navigationBarstatus bar,如 图17 所示。

图17

readableContentGuide & cellLayoutMarginsFollowreadableWidth

iOS9 就提出了 readableContentGuide 这一律念,主要是用于一些阅读类应用,在可视宽度较大的时候,但愿可以经过布局将阅读区域限定在必定范围,已缓解用户阅读的过程当中追踪内容移动头部所形成的疲劳。readableContentGuide 的间距大小会随着字体大小、设备不一样等因素而发生改变。现这一属性一样兼容 safeAreaInsets。一样的 UITableViewcellLayoutMarginsFollowreadableWidth 属性也一样兼容 safeAreaInsets,如 图1八、1九、20 所示。

图18

图19

图20

insetsContentViewToSafeArea

UITableView在iOS11开始添加了一个新的属性insetsContentViewsToSafeArea,该属性可以控制 TableViewCellContentView 是否被 safeAreaInsets 所影响,如 图20、21 所示。

图21

图22

底部按钮布局最佳实践

iPhone X 以后,咱们在开发过程当中常常会遇到如何布局底部按钮的问题。在本 Session 中官方给出了一种方案,例如设置按钮距底部相对于 superView 的约束为16,约束的 Priority 为 999,同时设置按钮底部相对于 safeAreaLayoutGuide 的约束值为大于等于 0。便可实现按钮在 iphone X 和 其余设备上的不一样布局,如 图23 所示。

图23

总结

其实本 Session 并无提出任何新的属性和方法,最新的属性在 iOS11 SDK 中就已经提出来了。可能不少开发者,在适配iPhone X 的时候遇到的问题也都解决的差很少了。但我的认为这个 Session 仍是颇有必要的,它将现有的用于适配开发的 UIKit SDK 进行了概括总结,这将有助于开发者进一步了解这些属性之间的关联关系对快速适配多种尺寸设备的项目开发会有很大帮助。

查看更多 WWDC 18 相关文章请前往 老司机x知识小集xSwiftGG WWDC 18 专题目录

相关文章
相关标签/搜索