1. 程式人生 > >iOS開發 關於iPhone X 的適配

iOS開發 關於iPhone X 的適配

1.螢幕尺寸相關變化

  1. 高度增加了145pt,變成812pt.
  2. 螢幕圓角顯示,注意至少留10pt邊距。
  3. 狀態列高度由20pt變成44pt,留意這個距離就能避開“劉海”的尷尬,相應的導航欄以上變化64->88。
  4. 底部工具欄需要為home indicator留出34pt邊距。
  5. 物理解析度為1125px * 2436px.

2.橫豎屏安全區對比

3.其他裝置安全區域對比

4.應用設計

5.控制元件佈局

如何讓APP適配?

APP啟動樣式適配

相信有一部分道友的APP在iPhone X上執行時並沒有像想象中那樣佔滿整個螢幕, 而是保持著原有的高度 在螢幕中心位置, 針對這個問題 目前經過實驗得出可以通過以下方式使APP按照全屏模式執行:

  1. 通過LaunchScreen.storyboard方式啟動
  2. 如果使用的是Assets中的LaunchImage, 在增加了iPhone X尺寸的圖片配置後.

LaunchScreen.storyboard方式不用多說, 這裡說一下如何在LaunchImage中增加iPhone X尺寸的圖片配置.

準備一張尺寸:1125 * 2436的啟動圖片, 移動到LaunchImage的Finder目錄中, 並在LaunchImage中的Contents.json檔案中增加 (注意Json格式):

{
    "extent" : "full-screen",
    "idiom" : "iphone",
    "subtype" : "2436h",
    "filename" : "圖片名.png",
    "minimum-system-version" : "11.0",
    "orientation" : "portrait",
    "scale" : "3x"
}

按照以上方式配置就完全解決了這個問題.

APP內部樣式適配

iOS11為UIViewControllerUIView增加了兩個新的屬性safeAreaInsetssafeAreaLayoutGuide, 通過這兩個屬性我們可以獲得安全區域的範圍, 通過上圖可以很清楚的看到安全區域的範圍, 我們要做的是讓那些不能被遮擋的內容和控制元件在安全區域範圍內顯示, 注意!這句話非常重要.

  • safeAreaInsets 適用於手動計算.
  • safeAreaLayoutGuide 適用於自動佈局.

Frame佈局方式適配示例

一般來說 可以通過在原有檢視座標計算時加入安全區域的範圍值, 下面舉個例子:

一個APP 它的NavigationBar使用的是自定義的UIView, 並非UINavigationBar, 這個自定義的UIViewframe屬性為CGRectMake(0, 0, 375, 64).
這樣的UIView在其他裝置上是沒有問題的, 標準的導航欄尺寸, 但是如果執行在iPhone X上 你會發現看上去無比的彆扭, 因為異形螢幕會造成部分顯示內容的遮擋問題, 這時候就要用到安全區域這個概念來解決這一問題.

先說一說通常自定義導航欄的結構, 高度是為64 由44高度的導航欄內容區域和20高度的狀態列區域(電池條那部分 status bar)組成, 44高度的導航欄內容區域用來顯示導航欄上的控制元件, 如返回按鈕 標題檢視等等, 現在, 在iPhone X上, 原來的狀態列(status bar)高度不再考慮了, 取而代之的是安全區域頂部間距safeAreaInsets.top, 我們將原有的結構改為 安全區域頂部距離螢幕的距離safeAreaInsets.top + 導航欄內容區域44, 這樣完成了一個自定義導航欄檢視在iPhone X上的適配.

下面是適配前後的效果對比:

再來看一下適配後的自定義導航欄檢視的UI結構

這只是舉一個簡單的例子, 因為不同的應用設計都是不同的, 但是適配的思路都是一樣的, 還是那句話 我們要做的是讓那些不能被遮擋的內容和控制元件在安全區域範圍內顯示, 在計算佈局時 將安全區域這個新特性考慮進去, iPhone X的適配也不是難事.

說一下在程式碼中的安全區域的適配該如何去寫:

iOS11 為UIViewControllerUIView增加了一個新的方法 - (void)viewSafeAreaInsetsDidChange;

這個方法如名字一樣 在安全區域改變後會被呼叫, 我們可以在需要適配的UIViewControllerUIView中重寫這個方法, 並且在這個方法中來根據safeAreaInsets屬性更新子檢視控制元件的佈局位置.

這裡有一點要注意的是當UIViewController呼叫- (void)viewDidLoad時它的所有子檢視的safeAreaInsets屬性都等於UIEdgeInsetsZero, 也就是說在- (void)viewSafeAreaInsetsDidChange;方法呼叫前 是無法通過當前檢視控制器的子檢視獲取到safeAreaInsets的, 不過獲取當前window物件的safeAreaInsets屬性用來計算也是可以的, 但是不建議這麼做, 一個檢視控制器的子檢視的處理當然要以它所在的控制器為準.

- (void)viewSafeAreaInsetsDidChangeUIViewController中第一次呼叫的時間是在- (void)viewWillAppear:(BOOL)animated呼叫之後, 在- (void)viewWillLayoutSubviews呼叫之前.

當然如果你要改變一個UIViewControllersafeAreaInsets值, 可以通過設定addtionalSafeAreaInsets屬性來實現, 例如你要自定義一些特殊的樣式時.

如果你改變了一個UIViewControllersafeAreaInsets屬性值, - (void)viewSafeAreaInsetsDidChange也會被呼叫.

另外, 給道友們的分享一個獲取某View安全區域範圍的巨集

#define VIEWSAFEAREAINSETS(view) ({UIEdgeInsets i; if(@available(iOS 11.0, *)) {i = view.safeAreaInsets;} else {i = UIEdgeInsetsZero;} i;})

使用起來比較簡潔

VIEWSAFEAREAINSETS(view).left

VIEWSAFEAREAINSETS(self.view).right

AutoLayout佈局方式示例

iOS11以前,我們佈局時, 檢視的 top 和 bottom 一般參照的是 Top Layout Guide 和 Bottom Layout Guide.

iOS11以後, 那兩個參照已經 deprecated (過時)了, 而是被Safe Area所取代.

總結

還是那句話 我們要做的是讓那些不能被遮擋的內容和控制元件在安全區域範圍內顯示.

感謝LEE