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 所示。app

圖4

佈局邊距

iOS8 中提出了 layoutMargins 的概念,其主要用於設置子視圖與父視圖之間的邊距,在 iOS11 中新增了 directionalLayoutMargins,主要爲了 Right To Left(RTL)語言下能夠進行自動適配。默認狀況下,layoutMargin 到各邊的距離是8個點。經過在 Interface Builder 裏面勾選 Constrain to margins 它會根據版本在 iOS11 及以上的系統中自動使用 directionalLayoutMargins,如 圖五、6 所示。iphone

圖5

圖6

安全區域和佈局邊距協同做用

正常狀況下子視圖的佈局邊距會依賴父視圖的安全區域,可是當設置了insetsLayoutMarginsFromSafeArea = false 以後,子視圖能夠達到突破父視圖安全區域的佈局效果,如 圖七、8 所示。ide

圖7

圖8

佈局之子視圖傳播

當一個視圖的preservesSuperviewLayoutMargins屬性爲 true 時,在對它的子視圖進行佈局時,父視圖的 margin 也會被考慮在內。若是存在一個子視圖的 frame 恰好和父視圖的 margin 表示區域有重合,此時設置 preservesSuperviewLayoutMargins 爲 true ,則子視圖會被恰好限制在父視圖的 margin 內,如 圖九、10 所示。佈局

圖9

圖10

最小邊距

UIViewController 存在屬性 systemMinimumLayoutMargins,能夠對其進行重寫,默認狀況下 view 的佈局邊距會受這個屬性的返回值制約。以下重寫了該屬性,則 view 的邊距最小會爲 [20,20,20,20]。性能

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 專題目錄

相關文章
相關標籤/搜索