一個自適應界面應該響應trait和size變化。在視圖控制器基本,使用trait大體上決定你所展示的內容和內容的布局。例如,當size類改變,你會選擇改變視圖屬性,顯示或隱藏視圖,或者顯示一組完全不同的視圖。在做出這些重大決策,使用size變化來調整你的內容。
自適應trait變化
trait提供一種方式,可以針對不同的環境以不同的方式配置app,可以使用它們來粗略的調整界面。大部分情況下,可以直接在storyboard文件中修改trait,但是有些需要額外的代碼。
配置storyboard處理不同size類
界面構建器使界面自適應不同size類變得更容易。storyboard編輯器支持配置不同的size類顯示界面,刪除視圖的具體配置,指定不同布局約束。還可以創建圖像asset為不同size類提供不同圖像。使用這些工具意味著不需要在運行時以編程的方式改變。相反,當當前size類改變,UIKit自動更新界面。
圖13-1展示了在界面構建器中用于配置界面的工具。size類查看控制改變界面視圖的外觀。使用該控制可以查看給定一個size類的界面外觀。對于個人視圖,使用安裝控制來配置該視圖是否存在給定size類配置。使用復選框左邊的加號(+)按鈕添加新的配置。
注意:未卸載的視圖仍然在視圖層級結構中,可以正常操作,但他們不會出現在屏幕上。
圖片asset是存儲應用圖片資源的首選方法。每個圖片asset包含相同圖片的多個版本,每個版本用于特定配置。除了為標準和Retina顯示指定不同的圖片,還可以為不同水平和垂直size類指定不同圖片。當配置了圖片asset,UIImageView對象自動根據當前size類和分辨率選擇圖片。
圖13-2 展示了圖片asset屬性。改變寬度和高度屬性會在圖片目錄中添加slot,為每個size類對應的slot添加圖片。
改變子視圖控制器的trait
子視圖控制器默認繼承他們父視圖控制器的trait。如size類,使每個子視圖控制器與父視圖控制器有相同的trait沒有意義。例如,在普通環境中的視圖控制器可能希望給一個或多個子視圖分配一個緊湊的size類,減少子視圖的空間。當實現一個容器視圖控制器,通過調用容器視圖控制器的setOverrideTraitCollection:forChildViewController:方法修改子視圖的trait。
列表13-1展示了如何創建一組新的trait,并將其關聯到子視圖控制器。只需在父視圖控制器中執行一次該代碼。覆蓋子視圖的trait直到再次改變trait或者從視圖控制器層級結構中刪除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>
當改變父視圖控制器的trait,子視圖繼承任何沒有顯式覆蓋父類的trait。例如,當父視圖控制器的水平size類從常規變成緊湊,在前面例子中的視圖控制器保持其常規水平size類。然而,如果displayScale trait改變,子視圖繼承新值。
presented視圖控制器自適應新樣式
presented視圖控制器在水平常規和緊湊環境中自適應。當從水平常規環境過渡到水平緊湊環境時,UIKit默認改變內置present風格為 UIModalPresentationFullScreen。對于自定義present風格,present控制器可以決定適應行為并根據情況調整。
對于一些app,采用全屏風格可能存在問題。例如,通常點擊其他區域,彈窗dismiss,但在緊湊環境中不可能這樣做,彈窗覆蓋整個屏幕,如圖13-3所示。當默認自適應風格不合適,可以告訴UIKit使用不同的風格或者present一個完全不同視圖控制器,使之更適合全屏風格。
要改變present風格的默認自適應行為,分配 delegate 到相關present控制器。使用presented視圖控制器的 presentationController 屬性訪問presentation控制器。presentation控制器在做出自適應相關更改前查詢代理對象。代理可以返回不同Presentation風格,而不是默認的。代理可以提供Presentation控制器另一個要顯示的視圖控制器。
使用代理的adaptivePresentationStyleForPresentationController: 方法指定不同presentation風格而不是默認風格。當過渡到緊湊環境時,僅支持的樣式是兩種全屏風格或UIModalPresentationNone。返回UIModalPresentationNone告訴Presentation控制器忽視緊湊環境并繼續使用前面的Presentation風格。如果是彈窗,忽視變更,提供類似iPad上的彈窗。在圖13-4中展示了默認全屏自適應和不適應,這樣你可以比較present結果。
要完全取代視圖控制器,實現代理的presentationController:viewControllerForAdaptivePresentationStyle: 方法。當自適應緊湊環境時,使用該方法插入導航控制器到視圖層級結構或者加載為小空間設計的視圖控制器。
實現自適應popover的提示
當從水平常規變為水平緊湊環境時,彈窗需要額外的修改。水平緊湊默認將彈窗改為全屏present。通常通過點擊彈窗外區域dismiss彈窗,當變為全屏present時無法dismiss彈窗。可以通過以下方式實現:
- push彈窗的視圖控制器到存在的導航堆棧上。當父導航控制器可用時,dismiss彈窗并將其視圖控制器push到導航堆棧上。
- 當全屏時,添加控件dismiss彈窗。可以添加控件到彈窗的視圖控制器上,但更好的選擇是使用presentationController:viewControllerForAdaptivePresentationStyle: 方法將彈窗從導航控制器中移除。使用導航控制器,則有一個模態界面和空間可以添加完成按鈕或其他控件dismiss內容。
- 使用present控制器代理消除任何自適應變化。獲取彈窗present控制器并分配代理實現adaptivePresentationStyleForPresentationController:方法。該方法返回 UIModalPresentationNone,導致彈窗繼續顯示為一個彈窗。更多信息,參見presented視圖控制器適應新風格(Adapting Presented View Controllers to a New Style)。
響應size變化
size發生變化的原因有很多,包括以下幾點:
- 底層窗口的尺寸改變,通常因為方向改變。
- 父視圖控制器調整子視圖控制器的size。
- present控制器改變presented視圖控制器的size。
當size發生變化時,UIKit通過正常布局過程,自動更新可見視圖控制器的size和position。如果使用Auto Layout約束指定視圖的size和position,app自適應任何size變化并運行在不同屏幕尺寸的設備上。
如果Auto Layout約束不能滿足你的要求,可以使用viewWillTransitionToSize:withTransitionCoordinator:方法改變布局。還可以使用該方法創建額外動畫。例如,在界面旋轉過程中,使用過度協調器的targetTransform 屬性來創建界面的逆轉矩陣。