在iPhoneX上适配你的App

在iPhone X上构建你的APP

原文链接,文章为 Building Apps for iPhone X Fall 2017 - Session 201 - iOS 的文字实录。以视频中主人公为第一视角,结合本文作者的一些理解的进行了内容讲解。

iPhone X

前言

要适配你的App,只需按照 iOS11 SDK 进行修改,就可以充分利用iPhone X搭载的超视网膜显示屏。


如果你的App主要基于标准的 UIKit 控件,并且使用 AutoLayout 那么接下来的任务就会很轻松了,因为绝大多数工作都由 UIKit 为你代劳了。


如果你使用的是自定义控件没有使用 AutoLayout ,再或者你的 App 是一款自定义全屏的 App 像很多游戏那样,你也不必担心,虽然你确实有些工作要做。但整个适配过程中并没有什么难点,而且我们有很多内建支持工具,比如全新推出的 Safe Area Layout Guide


无论如何,你都需要全面测试你的 App,尤其是在横屏模式下,以确保万无一失。

iPhone X Simulator

最新版 Xcode 包含支持 iPhone X 的 模拟器 让你可以改变绝大多数的布局, 尤其是调整关于 Safe Area 的布局。对于一些 App, 比如使用了 Metal 或是使用了前置摄像头等硬件功能的 App ,最好在实际设备上进行测试。


让我们来看看全新的 iPhone X Simulator:

iPhoneX

同其他 iPhone 或 iPad Simulator 一样,你可以直接使用系统内置 App,这样就可以很好的通过实例观察不同的 UIKit 组件在 iPhone X 上的表现。


比如文件App,就展示了很多最新的 iOS11 API 的实际应用。比如一体式的 SerchBar 和 Large NavigationBar Titles 。


别忘了,你还可以在 Simulator 中登录 iCloud 帐户,并访问你的 iCloud Drive 。这样你就可以方便的将文件或者照片等测试文件传输到 Simulator 中。

iCloud

另外一个不错的例子就是通讯录,它展示了 TableView 如何在 iPhone X 上呈现。一定要将 Simulator 旋转至横向模式。这样就可以看到一些效果,比如 Section Header 横跨屏幕,而 TableViewCell 则遵照 SafeArea 的原则,并保持缩进。稍后还会讲到 TableView 。

Address

接下来我们来看看我负责的项目 WWDC App,我花了一点时间,让它适配 iPhone X,我想分享一下我遇到的有关布局的问题以及我的解决方案。

适配 iPhone X

WWDC是一款真实存在的App,它已经面世了很多年。这些年来,很多工程师都参与了它的编写。它既有很多标准控件和 AutoLayout,也包含自定义View。App 中较老的部分甚至使用了手动布局。我会用这款 App 来强调三处需要针对 iPhone X 进行适配的地方。


首先,我在 Xcode 9 中打开工程文件,将 Base SDK 设为 iOS11,这样就可以以原生分辨率运行 App 了。


当设置你的 App 时,如果你发现 App 没有完整在 iPhone X 下运行,请检查一下你是否配置了 Launch Storyboard,因为这部分设置是必须的。(编辑注: 如果没有使用Launch Storyboard的话)


我们的初始视图是 Videos 标签页,效果如下图看起来还不错。这些全部使用的是今年的新代码,其中使用了遵循 AutoLayout 的 UICollectionView,以及 UINavigationBar 和 UIToolBar 控件等。所以绝大多数界面的布局都没问题,因为 UIKit 为我代劳了大部分工作。

有一个地方没有使用 AutoLayout ,那就是 News 标签页。效果如下图,其实这个 View 看起来还不错,尽管所有 UI 都是手动布局,尽管我们没有直接使用 AutoLayout,负责布局的代码也会注意到 layout margin insets,UIKit 会自动调整布局适应 Safe Area

AutoLayout 适配 Safe Area

我遇到的第一个适配问题就是再 News 标签页中的全屏图片浏览器。尽管这个 View 使用了 AutoLayout ,但其中 PageControl 的位置太靠下了,已经与主屏幕指示器重叠在了一起。


这里的主要问题在于页面空间的底部约束关联的是 SuperView ,也就是 Home 指示器后面的整个屏幕。所以,我们不应该根据父视图进行约束,而应该将 PageControl 按照底部的 Safe Area Layout Guide 进行约束。修改方式如下:

在调整约束前,需要先启用 StoryBoard/Xib 的 Safe Area Layout Guide。Xcode 9 以前的 StoryBoard/Xib 不会自动启用该选项。需要进入 文档检查器 -> Interface Builder Document -> 勾选 Use Safe Area Layout Guides 复选框

注意: iOS StoryBoard 打开 Use Safe Area Layout Guides 功能会自动升级绑定在 top 和 bottom 的 layout guide 约束,leading Edge 以及 trailing Edge。因此,勾选后一定要检查测试所有 AutoLayout 的约束。

Storyboard Safe Area

将如图所示右侧的 Use Safe Area Layout Guide 勾选上。

勾选之后,效果如下:



多出一个叫 Safe Area 的区域,如上图所示。

此时我们来看下 PageControl 的约束,之前约束都是与 SuperView 构建的关系,现在全部变成了 Safe Area。这样就不会遮挡 Home 指示器了。 怎么样很简单吧?


Xib Safe Area

操作步骤与 Storyboard 相同

  1. 先勾选 Use Safe Area Layout Guide
  2. 再修改 PageControl 的 bottom 约束,将 SuperView 改成与 Safe Area

操作步骤如gif图


经过上述调整,我们的 PageControl 就已经不再遮挡 Home 指示器了,并且在横竖屏下均有效。


SearchBar 适配问题

接下来,来看看我遇到的第二个问题。问题出在 Videos 标签页,同样看上去也还不错,但当我调出 SearchBar 时,看起来位置似乎有问题,让我们和通讯录进行一下对比。


SearchBar 的背景颜色似乎不太对,Size 也不太对。如果我旋转到横屏模式,可以看出 SearchBar 和 Cancel 按钮都被屏幕的圆角裁剪掉了一部分。


这个例子说明 Safe Area 的存在显得至关重要,对于这种搜索栏 WWDC 的做法是直接显示了一个 UISearchController ,而在 iOS 11 中 SearchBar 可以集成在 NavigationBar 中,并且给出正确的显示方式。让我们来看下代码如何修改:


这是显示 SearchController 的代码,需要做两处改动。

  1. 将 searchController 赋值给 navigationItem.searchController
  2. 让 searchController 变为活跃状态

注意: 该过程只在 iOS 11 下有效,因此,其他版本保持原有行为。

修改前:

    fileprivate func presentSearchController(initialSearchTeat searchTest: String? = nil) {
        let searchController = UISearchController(searchResultsController: nil)
        searchController.searchResultsUpdater = self as? UISearchResultsUpdating
        searchController.obscuresBackgroundDuringPresentation = false
        searchController.searchBar.text = searchTest
        
        present(searchController, animated: true, completion: nil)
    }

修改后:

    fileprivate func presentSearchController(initialSearchTeat searchTest: String? = nil) {
        let searchController = UISearchController(searchResultsController: nil)
        searchController.searchResultsUpdater = self as? UISearchResultsUpdating
        searchController.obscuresBackgroundDuringPresentation = false
        searchController.searchBar.text = searchTest
        
        if #available(iOS 11.0, *) {
            self.navigationItem.searchController = searchController
            searchController.isActive = true
        } else {
            present(searchController, animated: true, completion: nil)
        }
    }

现在 SearchBar 刚好在 Safe Area 中,并且这全部是 NavigationBar 自动帮我们处理的。如果你的 UI 效果中有 SearchBar 在 navigationBar 上的话,你一定要在 iOS 11 上做类似的处理。

TableView 适配问题

现在我们来看看 App 中的第三处改动,需要改进的地方。


如下是 Schedule 标签页,我们使用了 UITableView ,布局在竖屏模式下看起了不错,但这里搜索栏的样式也不太对。这个搜索栏恰好是作为 Header 视图插入到 TableView 中的。但我们可以像刚才那样改动,也就是让 SearchBar 集成到 NavigationBar 中。

布局切换到横屏模式所有UI看上去都遵循了 Safe Area 布局,但仔细观察 TableView 的 SectionHeader ,它自定义的 BackgroundColor 似乎有问题,颜色应该像通讯录 App 里的 TableView 那样一直延伸到屏幕边缘。

运行下代码会发现,App 将背景颜色设置给了 headerView 的 contentView ,这看上去很合理。

    func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
        let header = view as! UITableViewHeaderFooterView
        let font = UIFont.preferredFont(forTextStyle: .headline)
        
        header.textLabel?.font = font
        
        header.contentView?.backgroundColor = UIColor.lightGray
    }

事实上,在除了 iPhone X 之外的 iPhone 上都没有这个问题。那问题出在了哪里呢?

我们要研究下 TableView 在 iPhone X 上是如何布局 Cell 的。

原理

为了帮助大家理解,我们通过 Xcode 的 View Hierarchy Debugger 进行视图层级的查看。


这是我们刚刚看到的视图,通过 View Hierarchy Debugger 可以调节视图的层级和控制视图的显示/隐藏。

只显示 TableView ,你会发现它的尺寸是整个屏幕。

调节可见范围来显示 TableView 的 Cell 。

你会发现 Cell 是与屏幕一样宽的。

选中其中一个 Cell。

再用 Safe Area 来表示它的位置。

继续调节可见范围,我们可以看到 Cell 的 contentView ,自动布局在了 Safe Area 中。

虽然 Cell 的 Size 与屏幕一样,但 Cell 的 contentView 却和 Safe Area 的 Size 相同。
这样发生了刚刚我们发现的问题。

刚刚我们看到的界面有些混乱,我们进行一些简化并加上一些标记。

默认情况下,TableViewCell 会包含 ContentView,这样就可以将内容适配在 Safe Area 内部。但这种行为是可以由你控制的。

在 Xcode 中你可以勾选 ContentView 的 Insets To Safe Area 选项,代码中也有对应的属性可以设置。如果不勾选或不设置,contentView 就不会适配 Safe Area,而是会与 cell 一样大小。

无论 ContentView 如何设置,它的 Layout Margin 始终默认与 Safe Area 关联。与 ContentView 适配类似,也有一些属性可以让你控制 Layout Margin 。关于这一点以及其他与边距相关的选项你可以查阅文档以及 WWDC 视频。

解决方案

已经知道了原因是 Cell 的 contentView 的 Size 是与 Safe Area 相同的。通过代码我们可以了解到,我们只设置了 contentView 的背景颜色。此时,我们有几种解决方案来解决这个问题。
其中一种是禁用 TableView 的默认将 ContentView 适配 Safe Area 的行为,但这样会影响 contentView 里的其他内容。
这里最好的解决方案就是设定 backgroundView 的 backgroundColor。backgroundView 与 contentView 不同,它与 Cell 是一样大小,不受 Safe Area 影响。

    func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) {
        let header = view as! UITableViewHeaderFooterView
        let font = UIFont.preferredFont(forTextStyle: .headline)
        
        header.textLabel?.font = font
        
        header.backgroundView?.backgroundColor = UIColor.lightGray
    }

修改完毕后,编译运行。颜色就充满了整个 Cell 。但 ContentView 中的内容并没有发生变化。


以上就是我在为 WWDC 适配 iPhone X 的时候遇到的三个问题示例。

总结

适配 iPhone X ,需要注意以下几点:

  • 遵循 iOS 11 SDK,使用 Launch Storyboard,可以让你的 App 与原生分辨率一致
  • 测试UI时,横竖屏幕都要进行,绝大多数问题出在横屏下(左右横屏都要测)
  • 遵循 Safe Area 可以避免绝大多数适配问题
    • AutoLayout: 设置 safeAreaLayoutGuide
    • 手动布局: 使用 safeAreaInsets ,自由计算所需布局的数据
  • 不要让控件遮挡屏幕底部的 Home 指示器

关于 Home 指示器以及 iPhone X 设计方面的内容,请查看

Session Name Session Number From
Designing for iPhone X Session 801 Fall 2017
AutoLayout Techniques in Interface Builder Session 412 WWDC 2017
Modern User Interaction on iOS Session 219 WWDC 2017
Updating Your App for iOS 11 Session 204 WWDC 2017

一定要看 Designing for iPhone X 这个 Session,因为有很多关于 iPhone X 适配的细节包含在其中。

版权声明: QC-L, 如需转载请联系作者并标明出处,谢谢

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容