在iPhone X上構建你的APP
原文鏈接,文章為 Building Apps for iPhone X Fall 2017 - Session 201 - iOS 的文字實錄。以視頻中主人公為第一視角,結合本文作者的一些理解的進行了內容講解。
前言
要適配你的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:
同其他 iPhone 或 iPad Simulator 一樣,你可以直接使用系統內置 App,這樣就可以很好的通過實例觀察不同的 UIKit 組件在 iPhone X 上的表現。
比如文件App,就展示了很多最新的 iOS11 API 的實際應用。比如一體式的 SerchBar 和 Large NavigationBar Titles 。
別忘了,你還可以在 Simulator 中登錄 iCloud 帳戶,并訪問你的 iCloud Drive 。這樣你就可以方便的將文件或者照片等測試文件傳輸到 Simulator 中。
另外一個不錯的例子就是通訊錄,它展示了 TableView 如何在 iPhone X 上呈現。一定要將 Simulator 旋轉至橫向模式。這樣就可以看到一些效果,比如 Section Header 橫跨屏幕,而 TableViewCell 則遵照 SafeArea 的原則,并保持縮進。稍后還會講到 TableView 。
接下來我們來看看我負責的項目 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 相同
- 先勾選
Use Safe Area Layout Guide
- 再修改 PageControl 的 bottom 約束,將 SuperView 改成與 Safe Area
操作步驟如gif圖

經過上述調整,我們的 PageControl 就已經不再遮擋 Home 指示器了,并且在橫豎屏下均有效。
SearchBar 適配問題
接下來,來看看我遇到的第二個問題。問題出在 Videos 標簽頁,同樣看上去也還不錯,但當我調出 SearchBar 時,看起來位置似乎有問題,讓我們和通訊錄進行一下對比。
SearchBar 的背景顏色似乎不太對,Size 也不太對。如果我旋轉到橫屏模式,可以看出 SearchBar 和 Cancel 按鈕都被屏幕的圓角裁剪掉了一部分。
這個例子說明 Safe Area 的存在顯得至關重要,對于這種搜索欄 WWDC 的做法是直接顯示了一個 UISearchController ,而在 iOS 11 中 SearchBar 可以集成在 NavigationBar 中,并且給出正確的顯示方式。讓我們來看下代碼如何修改:
這是顯示 SearchController 的代碼,需要做兩處改動。
- 將 searchController 賦值給 navigationItem.searchController
- 讓 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
,自由計算所需布局的數據
- AutoLayout: 設置
- 不要讓控件遮擋屏幕底部的 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, 如需轉載請聯系作者并標明出處,謝謝