一個(gè)自適應(yīng)界面應(yīng)該響應(yīng)trait和size變化。在視圖控制器基本,使用trait大體上決定你所展示的內(nèi)容和內(nèi)容的布局。例如,當(dāng)size類改變,你會(huì)選擇改變視圖屬性,顯示或隱藏視圖,或者顯示一組完全不同的視圖。在做出這些重大決策,使用size變化來調(diào)整你的內(nèi)容。
自適應(yīng)trait變化
trait提供一種方式,可以針對(duì)不同的環(huán)境以不同的方式配置app,可以使用它們來粗略的調(diào)整界面。大部分情況下,可以直接在storyboard文件中修改trait,但是有些需要額外的代碼。
配置storyboard處理不同size類
界面構(gòu)建器使界面自適應(yīng)不同size類變得更容易。storyboard編輯器支持配置不同的size類顯示界面,刪除視圖的具體配置,指定不同布局約束。還可以創(chuàng)建圖像asset為不同size類提供不同圖像。使用這些工具意味著不需要在運(yùn)行時(shí)以編程的方式改變。相反,當(dāng)當(dāng)前size類改變,UIKit自動(dòng)更新界面。
圖13-1展示了在界面構(gòu)建器中用于配置界面的工具。size類查看控制改變界面視圖的外觀。使用該控制可以查看給定一個(gè)size類的界面外觀。對(duì)于個(gè)人視圖,使用安裝控制來配置該視圖是否存在給定size類配置。使用復(fù)選框左邊的加號(hào)(+)按鈕添加新的配置。

注意:未卸載的視圖仍然在視圖層級(jí)結(jié)構(gòu)中,可以正常操作,但他們不會(huì)出現(xiàn)在屏幕上。
圖片asset是存儲(chǔ)應(yīng)用圖片資源的首選方法。每個(gè)圖片asset包含相同圖片的多個(gè)版本,每個(gè)版本用于特定配置。除了為標(biāo)準(zhǔn)和Retina顯示指定不同的圖片,還可以為不同水平和垂直size類指定不同圖片。當(dāng)配置了圖片asset,UIImageView對(duì)象自動(dòng)根據(jù)當(dāng)前size類和分辨率選擇圖片。
圖13-2 展示了圖片asset屬性。改變寬度和高度屬性會(huì)在圖片目錄中添加slot,為每個(gè)size類對(duì)應(yīng)的slot添加圖片。

改變子視圖控制器的trait
子視圖控制器默認(rèn)繼承他們父視圖控制器的trait。如size類,使每個(gè)子視圖控制器與父視圖控制器有相同的trait沒有意義。例如,在普通環(huán)境中的視圖控制器可能希望給一個(gè)或多個(gè)子視圖分配一個(gè)緊湊的size類,減少子視圖的空間。當(dāng)實(shí)現(xiàn)一個(gè)容器視圖控制器,通過調(diào)用容器視圖控制器的setOverrideTraitCollection:forChildViewController:方法修改子視圖的trait。
列表13-1展示了如何創(chuàng)建一組新的trait,并將其關(guān)聯(lián)到子視圖控制器。只需在父視圖控制器中執(zhí)行一次該代碼。覆蓋子視圖的trait直到再次改變trait或者從視圖控制器層級(jí)結(jié)構(gòu)中刪除trait。
列表13-1 改變子視圖控制器的trait
<pre><code>
UITraitCollection* horizTrait = [UITraitCollection
traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassRegular];
UITraitCollection* vertTrait = [UITraitCollection
traitCollectionWithVerticalSizeClass:UIUserInterfaceSizeClassCompact];
UITraitCollection* childTraits = [UITraitCollection
traitCollectionWithTraitsFromCollections:@[horizTrait, vertTrait]];
[self setOverrideTraitCollection:childTraits
forChildViewController:self.childViewControllers[0]];
</pre></code>
當(dāng)改變父視圖控制器的trait,子視圖繼承任何沒有顯式覆蓋父類的trait。例如,當(dāng)父視圖控制器的水平size類從常規(guī)變成緊湊,在前面例子中的視圖控制器保持其常規(guī)水平size類。然而,如果displayScale trait改變,子視圖繼承新值。
presented視圖控制器自適應(yīng)新樣式
presented視圖控制器在水平常規(guī)和緊湊環(huán)境中自適應(yīng)。當(dāng)從水平常規(guī)環(huán)境過渡到水平緊湊環(huán)境時(shí),UIKit默認(rèn)改變內(nèi)置present風(fēng)格為 UIModalPresentationFullScreen。對(duì)于自定義present風(fēng)格,present控制器可以決定適應(yīng)行為并根據(jù)情況調(diào)整。
對(duì)于一些app,采用全屏風(fēng)格可能存在問題。例如,通常點(diǎn)擊其他區(qū)域,彈窗dismiss,但在緊湊環(huán)境中不可能這樣做,彈窗覆蓋整個(gè)屏幕,如圖13-3所示。當(dāng)默認(rèn)自適應(yīng)風(fēng)格不合適,可以告訴UIKit使用不同的風(fēng)格或者present一個(gè)完全不同視圖控制器,使之更適合全屏風(fēng)格。

要改變present風(fēng)格的默認(rèn)自適應(yīng)行為,分配 delegate 到相關(guān)present控制器。使用presented視圖控制器的 presentationController 屬性訪問presentation控制器。presentation控制器在做出自適應(yīng)相關(guān)更改前查詢代理對(duì)象。代理可以返回不同Presentation風(fēng)格,而不是默認(rèn)的。代理可以提供Presentation控制器另一個(gè)要顯示的視圖控制器。
使用代理的adaptivePresentationStyleForPresentationController: 方法指定不同presentation風(fēng)格而不是默認(rèn)風(fēng)格。當(dāng)過渡到緊湊環(huán)境時(shí),僅支持的樣式是兩種全屏風(fēng)格或UIModalPresentationNone。返回UIModalPresentationNone告訴Presentation控制器忽視緊湊環(huán)境并繼續(xù)使用前面的Presentation風(fēng)格。如果是彈窗,忽視變更,提供類似iPad上的彈窗。在圖13-4中展示了默認(rèn)全屏自適應(yīng)和不適應(yīng),這樣你可以比較present結(jié)果。

要完全取代視圖控制器,實(shí)現(xiàn)代理的presentationController:viewControllerForAdaptivePresentationStyle: 方法。當(dāng)自適應(yīng)緊湊環(huán)境時(shí),使用該方法插入導(dǎo)航控制器到視圖層級(jí)結(jié)構(gòu)或者加載為小空間設(shè)計(jì)的視圖控制器。
實(shí)現(xiàn)自適應(yīng)popover的提示
當(dāng)從水平常規(guī)變?yōu)樗骄o湊環(huán)境時(shí),彈窗需要額外的修改。水平緊湊默認(rèn)將彈窗改為全屏present。通常通過點(diǎn)擊彈窗外區(qū)域dismiss彈窗,當(dāng)變?yōu)槿羛resent時(shí)無法dismiss彈窗??梢酝ㄟ^以下方式實(shí)現(xiàn):
- push彈窗的視圖控制器到存在的導(dǎo)航堆棧上。當(dāng)父導(dǎo)航控制器可用時(shí),dismiss彈窗并將其視圖控制器push到導(dǎo)航堆棧上。
- 當(dāng)全屏?xí)r,添加控件dismiss彈窗??梢蕴砑涌丶綇棿暗囊晥D控制器上,但更好的選擇是使用presentationController:viewControllerForAdaptivePresentationStyle: 方法將彈窗從導(dǎo)航控制器中移除。使用導(dǎo)航控制器,則有一個(gè)模態(tài)界面和空間可以添加完成按鈕或其他控件dismiss內(nèi)容。
- 使用present控制器代理消除任何自適應(yīng)變化。獲取彈窗present控制器并分配代理實(shí)現(xiàn)adaptivePresentationStyleForPresentationController:方法。該方法返回 UIModalPresentationNone,導(dǎo)致彈窗繼續(xù)顯示為一個(gè)彈窗。更多信息,參見presented視圖控制器適應(yīng)新風(fēng)格(Adapting Presented View Controllers to a New Style)。
響應(yīng)size變化
size發(fā)生變化的原因有很多,包括以下幾點(diǎn):
- 底層窗口的尺寸改變,通常因?yàn)榉较蚋淖儭?/li>
- 父視圖控制器調(diào)整子視圖控制器的size。
- present控制器改變presented視圖控制器的size。
當(dāng)size發(fā)生變化時(shí),UIKit通過正常布局過程,自動(dòng)更新可見視圖控制器的size和position。如果使用Auto Layout約束指定視圖的size和position,app自適應(yīng)任何size變化并運(yùn)行在不同屏幕尺寸的設(shè)備上。
如果Auto Layout約束不能滿足你的要求,可以使用viewWillTransitionToSize:withTransitionCoordinator:方法改變布局。還可以使用該方法創(chuàng)建額外動(dòng)畫。例如,在界面旋轉(zhuǎn)過程中,使用過度協(xié)調(diào)器的targetTransform 屬性來創(chuàng)建界面的逆轉(zhuǎn)矩陣。