适配 iPhone X 的正确姿势

swift 发布于 2019年09月16日

iPhone X 已经发布一段时间了,应该有不少朋友都拿到真机了。 而且会有越来越多的新用户诞生。 每年苹果新产品发布,都是开发者朋友们最繁忙的时间,要适配新的系统和设备。 特别今年 iPhone X 的发布,相当于一次比较大的更新。这次我帮大家把需要注意的细节做一个整理。

基本事项

首先, iPhone X 的屏幕布局和前几代 iPhone 相比发生了质的变化。 下面是一张模拟器的截图:

大家可以看到,至少有三个细节是非常明显的。

首先顶部的状态栏中间多了一个 “刘海”,这个黑色的区域是用来放置前置摄像头和感光器的。

另外一个细节,是屏幕底部多了一个横条, 因为 iPhone X 采用全面屏,没有 Home 键,屏幕底部的整个横条就相当于 Home 键的作用。

最后一个细节,就是 iPhone X 屏幕是圆角的,也许这个细节看似不那么重要, 但在某些特定情况下,就会产生很大影响。

下面我就针对 iPhone X 的这三个特性,和大家交流一下如何更好的适配。

顶部状态条

iPhone X 让我们第一眼辨识出来的,应该当属顶部这个状态条了,它的形状很特别。 我翻阅了一下新版的 iOS 人机交互指南, 苹果官方给出了我们如下几个建议。

状态条高度和之前不同

首先是 iPhone X 的状态条要比之前 iPhone 设备的要高。 以前几乎所有的 iPhone, 顶部状态条都是 20pt, 而新的 iPhone X 的顶部状态条要比这个高。 相信应该会有不少老代码会在布局视图的时候,假设状态条的高度是 20pt, 如果你的项目中有这类代码,就需要仔细检查一下了。

先说一个最简单的处理方法,加入之前你项目中有类似的代码:

topViewFrame = CGRect(x: 0, y: 20, width: self.view.frame.size.width, height: 50)

这里,topViewFrame 可以是放在当前视图顶部的一个导航视图的尺寸定义,CGRect 的 y 坐标是写死的 20,你可以用这种形式简单改写:

topViewFrame = CGRect(x: 0, y: UIApplication.shared.statusBarFrame.height, width: self.view.frame.size.width, height: 50)

UIApplication.shared.statusBarFrame.height 是当前系统状态栏的高度。 这样动态获取就可以解决大部分的状态条适配问题。 当然我刚才也说了这个是最简单的方法,当然算不上最优的方法。后面会给大家介绍官方推荐的另一种方案。

尽量不要隐藏状态条

另外一个官方的建议就是,尽量不要隐藏 iPhone X 的顶部状态条。 这点也不难想象。 以往我们开发 APP 的时候,隐藏状态条或者是为了增加 APP 的沉浸感,又或者是给我们的 APP 多占用一些屏幕空间。 但 iPhone X 的状态条正如大家看到的,即使你把它隐藏了,你也不太容易利用到多处的这部分空间,这块区域始终会有中间的那个黑色 "刘海“。 所以在 iPhone X 对大多数 APP 来说,隐藏顶部状态条的设计并没有多大意义,所以官方指南中也建议大家不要隐藏。

底部 Home 条

另外一个要说的就是底部的 Home 访问条。 iPhone X 没有实体 Home 按键,用户返回桌面的唯一方式就是通过这个 Home 条了。 所以 APP 需要给这个地方预留出空间。 如果你用的是系统标准组件,比如 UITableView,它们已经处理这些事情了。 但是如果是你自己构建的 UI, 就要格外注意这一点了。

下面两张截图说明了这个问题:

这张截图展示出,我们自定义的返回按钮,和底部 Home 条重叠了。 这个 UI 在其他的 iPhone 上是没问题的, 下面是普通 iPhone 上运行的截图:

但是因为 iPhone X 有这个底部 Home 条,所以适配的时候就需要特别注意, 这张截图是成功适配后的样子:

关于这点,苹果官方交互指南上也有明确的说明。 APP 自己的操作控件不要和底部的 Home Bar 重叠,否则会对用户体验造成影响,除了视觉上的影响之外。 对用户与系统 Home 条的交互也会产生影响。

总之,在开发新的 APP 时,要考虑到 iPhone X 底部 Home 条的这个问题。 那么如何对我们自定义的视图给 Home 条留出这个区域呢,我们没办法像顶部状态条那样直接获取它的高度。 所以就需要用到 iOS 11 新加入的 Safa Area,这个属性可以说是专门为 iPhone X 量身定制的,稍后我们会介绍到。

不要将交互控件放到圆角区域

iPhone X 的屏幕是圆角的, 所以我们在开发 APP 的时候也要考虑到这一点,以免因为某些假设,导致视图布局的错乱。 比如这张截图:

上图中的返回按钮,本来应该是矩形的,但是因为屏幕是圆角的,所以被裁剪了。 所以我们在适配 iPhone X 的时候同样要考虑到这个问题。

让我们来做个简单的总结,目前影响到 APP 适配 iPhone X 的三个因素分别是,顶部状态条,底部 Home 条和屏幕圆角区域。并且我们在前面的讨论中也都给出了部分的解决方案,比如对顶部状态条运行时的动态尺寸判断等,这些方案虽然能够解决适配的问题,但无疑会给我们的代码添加一层复杂度,可以使用,但并不优雅。

下面就和大家讨论另外一种解决方案,也就是 iOS 11 提供的 Safe Area 特性,在前面的内容中我们也提到过它。

使用 Safe Area

Safe Area 是 iOS 11 引入的一个新特性。 新版的 iOS SDK 为 UIView 提供了两个新属性 safeAreaLayoutGuidesafeAreaInsets。 从名字中大概也可以猜到,它给我们提供视图的安全显示区域。

所谓安全区域,就能保证这个视图和我们前面顶部状态条,底部 Home 条,以及圆角区域都不重合的区域,只要我们在视图内容显示在这个区域中,就不需要担心我们前面所列出的各种视图布局问题了。

比如我们前面列举的,顶部状态栏在 iPhone X 上的适配问题,可以用这个方法轻易的解决:

override func viewWillLayoutSubviews() {

super.viewWillLayoutSubviews()

if useSafeArea {

let safeInset = self.view.safeAreaInsets

let topFrame = CGRect(x: safeInset.left, y: safeInset.top, width: self.view.frame.size.width - safeInset.right, height: 50)
self.topView?.frame = topFrame

}

}

viewWillLayoutSubviews 方法是 UIViewController 的标准生命周期。 我们在这里引用 view 的 safeAreaInsets 属性,它可以标识出当前 view 的安全区域。

比如这里的 safeInset.top 表示在当前 view 顶部多少 pt 的区域是不可用的, 我们只需要依照 safeAreaInsets 返回的内容,调整视图布局就能保证当前视图不合系统控件冲突了。

这里说一下为什么要在 viewWillLayoutSubviews 中使用 safeAreaInsets。 这是因为这个属性只有在视图添加到 UI 上才会有正确的取值,如果我们把这段代码放到 viewDidLoad 中,它的取值会都是 0, 因为这时候视图还没有被添加到 UI 中,调用的时机很重要。

这里我们只说了 safeAreaInsets, 这个属性是对我们手动布局来使用的。 如果你使用的是 AutoLayout, 那么 safeAreaLayoutGuide 是对应的。

对于我们上面所列举的几种适配问题场景,Safe Area 都可以比较优雅的解决。 另外我专门写了一个例子列举出了几种适配场景:

大家可以直接在 Github 上面查看: https://github.com/swiftcafex/Samples/tree/master/iphonex

总结

这次给大家介绍了 iPhone X 适配的几个基本注意点,当然这里介绍的也只是最常用的一些地方。 如果深度适配还是需要做更多工作,推荐大家查看苹果官方的人机交互指南,https://developer.apple.com/ios/human-interface-guidelines/overview/iphone-x/, 里面有更多细节例子。

iPhone X 这次的升级幅度相比之前还是大了不少,也正因为这样也带来了更多的机会,如果大家感兴趣,就在下面尽情留言吧,我会持续帮助大家发掘它能做的事情分享出来。根据以往的经验,一般新机发布最先适配的 APP,都会吃到一些红利,如果你的 APP 还没有适配,就抓紧抢占这波机会吧。


如果你觉得这篇文章有帮助,还可以关注微信公众号 swift-cafe,会有更多我的原创内容分享给你~

本站文章均为原创内容,如需转载请注明出处,谢谢。
关注微信公众号
发现更多精彩
swift-cafe