標籤:http io os 使用 ar for strong sp div
在iOS8中,新增了Size Classes特性,它是對當前所有iOS裝置尺寸的一個抽象,也是該抽象了,想想現在多少種iOS尺寸的裝置吧:iPhone4-5-6-6plus、iPad、iPad mini、iWatch,如何還是按照以前那針對種特定裝置來編寫不同的布局的話,一定是很糟糕的一件事情。
現在有了sizeclass,事情就好辦多了:你不是裝置多嗎,那我們就只把螢幕的寬和高分別分成三種情況:(Compact, Regular, Any),也即緊湊、正常和任意。這樣寬和高三三一整合,一共9中情況。如所示,針對每一種情況,如果需要的話,我們可以單獨在storyboard或xib中設定UIView的自動布局約束,甚至某一個button是否顯示都是能輕鬆實現。
和 UIKit 中的響應者鏈正好相反,traitCollection 將會在 view hierarchy 中自上而下地進行傳遞。對於沒有指定 traitCollection 的 UI 組件,將使用其父節點的 traitCollection。這在布局包含 childViewController 的介面的時候會相當有用。在 UITraitEnvironment 這個介面中另一個非常有用的是 -traitCollectionDidChange:。在 traitCollection 發生變化時,這個方法將被調用。在實際操作時,我們往往會在 ViewController 中重寫 -traitCollectionDidChange: 或者 -willTransitionToTraitCollection:withTransitionCoordinator: 方法 (對於 ViewController 來說的話,後者也許是更好的選擇,因為提供了轉場上下文方便進行動畫;但是對於普通的 View 來說就只有前面一個方法了),然後在其中對當前的 traitCollection 進行判斷,並進行重新布局以及動畫。代碼看起來大概會是這個樣子:
- - (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection
- withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator
- {
- [super willTransitionToTraitCollection:newCollection
- withTransitionCoordinator:coordinator];
- [coordinator animateAlongsideTransition:^(id <UIViewControllerTransitionCoordinatorContext> context) {
- if (newCollection.verticalSizeClass == UIUserInterfaceSizeClassCompact) {
- //To Do: modify something for compact vertical size
- } else {
- //To Do: modify something for other vertical size
- }
- [self.view setNeedsLayout];
- } completion:nil];
- }
在兩個 To Do 中,我們應該刪除或者添加或者更改不同條件下的 Auto Layout 約束 (當然,你也可以幹其他任何你想做的事情),然後調用 -setNeedsLayout 來在上下文中觸發轉移動畫。如果你堅持用代碼來處理的話,可能需要面臨對於不同 Size Classes 來做移除舊的約束和添加新的約束這樣的事情,可以說是很麻煩 (至少我覺得是麻煩的要死)。但是如果我們使用 IB 的話,這些事情和代碼都可以省掉,我們可以非常方便地在 IB 中指定各種 Size Classes 的約束 (稍後會介紹如何使用 IB 來對應 Size Classes)。另外使用 IB 不僅可以節約成百上千行的布局代碼,更可以從新的 Xcode 和 IB 中得到很多設計時就可以即時監視,查看並且調試的特性。可以說手寫 UI 和使用 IB 設計的時間消耗和成本差距被進一步拉大,並且出現了很多手寫 UI 無法實現,但是 IB 可以不假思索地完成的任務。從這個意義上來說,新的 IB 和 Size Classes 系統可以說無情地給手寫代碼判了個死緩。 另外,新的 API 和體系的引入也同時給很多我們熟悉的 UIViewController 的有關旋轉的老朋友判了死刑,比如下面這些 API 都棄用了:
- @property(nonatomic, readonly) UIInterfaceOrientation interfaceOrientation
-
- - willRotateToInterfaceOrientation:duration:
- - willAnimateRotationToInterfaceOrientation:duration:
- - didRotateFromInterfaceOrientation:
- - shouldAutomaticallyForwardRotationMethods
現在全部統一到了 viewWillTransitionToSize:withTransitionCoordinator:,旋轉的概念不再被提倡使用。其實仔細想想,所謂旋轉,不過就是一種 Size 的改變而已,我們都被 Apple 騙了好多年,不是嗎?
在Xcode中的具體體現如:
但是我們看到圖中的寬度和高度都是Any,Any是什麼意思呢?如果weight設為Any,height設定為Regular,那麼在該狀態下的介面元素在只要height為Regular,無論weight是Regular還是Compact的狀態中都會存在。這種關係應該叫做繼承關係,具體的四種介面描述與可繼承的介面描述如下:
- w:Compact h:Compact 繼承 (w:Any h:Compact , w:Compact h:Any , w:Any h:Any)
- w:Regular h:Compact 繼承 (w:Any h:Compact , w:Regular h:Any , w:Any h:Any)
- w:Compact h:Regular 繼承 (w:Any h:Regular , w:Compact h:Any , w:Any h:Any)
- w:Regular h:Regular 繼承 (w:Any h:Regular , w:Regular h:Any , w:Any h:Any)
我們知道了iOS 8下面裝置介面可以描述為4種,但是這麼多裝置(iPhone4S,iPhone5/5s,iPhone6,iPhone6 Plus,iPad,Apple Watch)具體對應什麼描述呢?經過查看官方文檔和具體實踐得知具體對應關係如下:
- iPhone4S,iPhone5/5s,iPhone6
- 豎屏:(w:Compact h:Regular)
- 橫屏:(w:Compact h:Compact)
- iPhone6 Plus
- 豎屏:(w:Compact h:Regular)
- 橫屏:(w:Regular h:Compact)
- iPad
- 豎屏:(w:Regular h:Regular)
- 橫屏:(w:Regular h:Regular)
- Apple Watch(猜測)
- 豎屏:(w:Compact h:Compact)
- 橫屏:(w:Compact h:Compact)
Size Classes手寫代碼
為了表徵Size Classes,Apple在iOS8中引入了一個新的類,UITraitCollection。這個類封裝了像水平和豎直方向的Size Class等資訊。iOS8的UIKit中大多數UI的基礎類(包括UIScreen,UIWindow,UIViewController和UIView)都實現了UITraitEnvironment這個介面,通過其中的traitCollection這個屬性,我們可以拿到對應的UITraitCollection對象,從而得知當前的Size Class,並進一步確定介面的布局。和UIKit中的響應者鏈正好相反,traitCollection將會在view hierarchy中自上而下地進行傳遞。對於沒有指定traitCollection的UI組件,將使用其父節點的traitCollection。這在布局包含childViewController的介面的時候會相當有用。在UITraitEnvironment這個介面中另一個非常有用的是-traitCollectionDidChange:。在traitCollection發生變化時,這個方法將被調用。在實際操作時,我們往往會在ViewController中重寫-traitCollectionDidChange:或者-willTransitionToTraitCollection:withTransitionCoordinator:方法(對於ViewController來說的話,後者也許是更好的選擇,因為提供了轉場上下文方便進行動畫;但是對於普通的View來說就只有前面一個方法了),然後在其中對當前的traitCollection進行判斷,並進行重新布局以及動畫。代碼看起來大概會是這個樣子:
123456789101112131415 |
- (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator{ [super willTransitionToTraitCollection:newCollection withTransitionCoordinator:coordinator]; [coordinator animateAlongsideTransition:^(id <UIViewControllerTransitionCoordinatorContext> context) { if (newCollection.verticalSizeClass == UIUserInterfaceSizeClassCompact) { //To Do: modify something for compact vertical size } else { //To Do: modify something for other vertical size } [self.view setNeedsLayout]; } completion:nil];}
|
在兩個To Do處,我們要手寫代碼針對不同的狀態做調整。
Size Classes與Interface Builder
Xcode6中Interface Builder對Size Class有了很強大的支援,xib中可以開啟Size Classes如:
在不同的Size Classes描述下,介面元素可以選擇安裝還是不安裝,具體操作
Size Classes與Image Asset
Xcode6中Image Asset也支援了Size Class,也就是說,我們可以對不同的Size Class指定不同的圖片了。在Image Asset的編輯面板中選擇某張圖片,Inspector裡現在多了一個Width和Height的組合,添加我們需要對應的Size Class,然後把合適的圖拖上去,這樣在運行時SDK就將從中挑選對應的Size的圖進行替換了。支援Size Class的Image Asset編輯效果如下:
iOS8 Size Classes的理解與使用