翻譯:Building an Adaptive Interface-翻譯-size class和present view controller

寫在之前的大篇廢話

研究adaptivePresentationStyleForPresentationController和iPhone上popover一個popoverPresentationController的關系無果后,一怒之下翻譯該文檔,

希望不要浪費太多時間 -- 9月28號

結(jié)果學到了很多東西,雖然還沒解決問題 -- 9月29號

問題解決了,原來都在文檔里,只是我沒讀懂讀透 --9月30號


廢話:-----通過這次翻譯的經(jīng)歷,感覺到沉下心來做一件事的重要性,28號的時候無意間研究到iphone的popover,發(fā)現(xiàn)自己怎么也不能在iphone上做出一個popover出來,老是全屏,搗鼓了大半天,把度娘和谷歌翻了個遍,覺得確實是照著人家的帖子做的,為啥不出呢?

翻到ios官網(wǎng)的這篇文章,總覺得讀了沒有收獲,(我英語都認識,可是讀完也不知道它在說什么)但是又覺得它確實提到了我所說的問題,反正也挺無奈的,就決定逐字逐句的讀一讀這文章,看看是不是自己有什么沒懂的地方.

每句讀了也不了解的話,我都姑且照字翻譯了下,然后會去查閱相關的文檔,官網(wǎng)優(yōu)先,百度也問,也翻這本書:Programming.iOS.9.在逐步學習的過程中,發(fā)現(xiàn)了很多平時我掌握的似是而非的東西,如size classes,如vc間的present dismiss等等,雖然做ios已經(jīng)兩年了,這些東西每天都在弄,但是它很多細微的東西還沒有深入的了解.

慢慢的融會貫通幾個知識點,理解了很多東西,雖然這些東西平時沒人會問你為什么,找工作別人也不會問這么細,浪費時間想這些似乎沒有多大的意思,沒有弄些時尚流行的技術來得可以吹niub.但是還是感觸很深,很多簡單的功能,會做.但是為什么這么做,深層的意義在哪里,內(nèi)涵思想是什么,研究了這些細節(jié)后,才有所體會.之前還是很心浮氣躁,比如9月28號的時候,看了五六個帖子,覺得自己已經(jīng)會了popover的步驟,就是不出效果,快要放棄了.這兩天看了一些文檔,才領會了為啥這么做,為啥要寫代理,還可以舉一反三等等.讀的多了,發(fā)現(xiàn)某些大神的所謂深入帖子,也只是把官網(wǎng)的幾篇文檔綜合了一下,加上自己的總結(jié).可見編程其實和做學問差不多,要放下心中的浮躁,慢節(jié)奏的讀一些似乎沒用的東西.

問題的解決經(jīng)過:

之前照著這個帖子做的,http://m.itdecent.cn/p/e44542c38fc9 始終不能出現(xiàn)popover,總是全屏,我認為肯定是adaptivePresentationStyleForPresentationController這個函數(shù)出的問題,調(diào)試發(fā)現(xiàn)從來沒進入過,然后差點放棄了.

我也沒問過自己為什么一定要實現(xiàn)這個方法,原因是啥.就知道很多帖子都說了這個, 直到翻譯完了文檔,才知道:

其實在swift3中不是這個函數(shù)(OC中是上面那個函數(shù)),而是:

func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle{

return .none

}

1) 它是UIViewController的屬性presentationController的代理UIPresentationControllerDelegate的函數(shù).

2) 同理,UIViewController的屬性popoverPresentationController的代理UIPopoverPresentationControllerDelegate,由于繼承了UIPresentationControllerDelegate的原因,所以也要實現(xiàn)這個方法.

關系如圖1-1-1:

1-1-1

實現(xiàn)了它頓時就好了.所以坑就在這里

這是我的代碼:


@IBAction func clickBtn(_ sender: AnyObject) {

let pop = PopViewController()

//這個屬性必須實現(xiàn),否則popoverPresentationController為nil

pop.modalPresentationStyle = .popover

//設置代理,用 adaptivePresentationStyle(for controller) 指定不要全屏顯示

pop.popoverPresentationController?.delegate = self

//popover 的大小

pop.preferredContentSize = CGSize(width:100, height:100)

//popover基于哪個view出來

pop.popoverPresentationController?.sourceView = btn

pop.popoverPresentationController?.sourceRect? = CGRect.zero

//? ? ? ? pop.popoverPresentationController?.sourceRect? = CGRect(origin:CGPoint(x:100,y:100) ,size:CGSize(width:0,height:0))

//popover的箭頭方向

pop.popoverPresentationController?.permittedArrowDirections = .down

self.present(pop, animated: true, completion: nil)

}

xib或者storyboard里的pop 不需要做任何改動.比如這個帖子寫的https://my.oschina.net/sayonala/blog/533888 ?都不用

效果:

1-1-2


翻譯之前的儲備


1. size classes

1) size classes 是ios8引進的的一種對布局的自適應的解決方案.可以從以下兩個方面理解:

對不同設備的屏幕尺寸,包括橫屏和豎屏,我們可以設定不同的view布局,系統(tǒng)會檢測到具體的設備,幫我們自動切換對應的布局.

對同一套布局,系統(tǒng)會檢測到具體的設備和屏幕方向,遵循autoulayout的設定,自動布局.

于是我們可以無視具體設備的尺寸和屏幕方向,根據(jù)size classes 的規(guī)定來布局了.

2) ?在ios8后,蘋果定義所有設備的size class只分為兩種屬性: 詳見枚舉UIUserInterfaceSizeClass

. 普通的(Regular)

. 緊湊的(Compact)

Any包含了上面兩種情況. 所以nib中的width:Any和height:Any代表:包含了所有情況.

如果在ios8后看到這種判斷設備和尺寸的代碼:就不太好(ios7時我剛?cè)腴Tios,看到我們公司項目中這么寫的,當時沒有size classes)

//iphone4 and iphone4s

if (UIScreen.main.bounds.height == 480) {

}

//iphone5 and iphone5s

else if (UIScreen.main.bounds.height == 568) {

}

那么具體設備尺寸和 Compact,Regular的對應關系是?

這張圖1-1來自于UITraitCollection的api文檔 https://developer.apple.com/reference/uikit/uitraitcollection


1-1

總結(jié)下:

1) ipad不管橫豎寬高size class都是regular,?

2) iPhone橫著時寬高size class都是compact,豎起來高會變成regular.

3)iPhone 6plus特殊點,不管橫豎 長邊就是regular,短邊是compact ?... iphone7不畫,因為它尺寸和iphone6s沒有變化.


現(xiàn)在ios10 nib編程已經(jīng)不用背這個了,為啥,見圖13-1. 它把尺寸和設備都形象化了

如果用代碼,我們還是要了解對應關系的,不然我們獲取出來了屏幕width和height的size class,還不知道當前設備是個啥情況呢.


2. trait - UITraitCollection和其接口UITraitEnvironment

上面說取屏幕width和height的size class,如何取?取出來后,我們可以根據(jù)不同的尺寸和橫豎屏,更改布局,如隱藏或者顯示某些view等.

trait英文是特性的意思,我理解就是UITraitCollection.也就是關于尺寸,設備屏幕的一系列屬性的大集合.

https://developer.apple.com/reference/uikit/uitraitcollection 這是 UITraitCollection的官方文檔

UITraitCollection是接口UITraitEnvironment的屬性.它包含了設備關于屏幕的眾多trait,size class也是其中一個屬性:

1) 水平和豎直上的size class,horizontalSizeClass,verticalSizeClass

2) 顯示縮放比 displayScale

3) 用戶設備的分類 userInterfaceIdiom(枚舉UIUserInterfaceIdiom).

public enum UIUserInterfaceIdiom : Int {

case unspecified ?//未定義

case phone // iPhone and iPod touch style UI

case pad // iPad style UI

case tv // Apple TV style UI ?apple做電視和車載,我還沒看到大陸哪里有買哇-_-

case carPlay // CarPlay style UI

}

UIScreen, UIWindow, UIViewController, UIPresentationController,UIView都實現(xiàn)了UITraitEnvironment接口,因此可以很方便的直接取用:

self.traitCollection

兩個函數(shù),在trait發(fā)生改變時被調(diào)用:

1.public func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) ?

它是接口UITraitEnvironment的方法.上面提到的UIScreen, UIWindow, UIViewController, UIPresentationController,UIView都可以實現(xiàn)它.當trait發(fā)生改變時,進入這個方法.我們通過判斷其屬性改變布局:

代碼:

//MARK: UITraitEnvironment

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?)? {

//iphone 橫屏

if previousTraitCollection?.horizontalSizeClass == .compact &&? previousTraitCollection?.verticalSizeClass == .compact{

print("iPhone從橫屏->豎屏")

}

else if (previousTraitCollection?.horizontalSizeClass == .compact &&? previousTraitCollection?.verticalSizeClass == .regular){

print("iPhone從豎屏->橫屏")

}

}

注意:1) previousTraitCollection是之前的設備狀態(tài),不是當前的.而且有可能是nil,比如程序最開始啟動的時候還沒有之前狀態(tài)喲

? ? ? ? 2) 橫豎屏切換記得先打開手機設置中的橫豎屏開關


2.public func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator)

這個方法是接口UIContentContainer的方法,所幸UIViewControllerUIPresentationController都實現(xiàn)了它. 它也是在trait改變時進入的.它先于traitCollectionDidChange被調(diào)用.

可以在里面寫動畫coordinator.animateAlongsideTransition ...

要調(diào)用super.willTransition(to: newCollection, with: coordinator). ?除非自己實現(xiàn)子viewcontroller的變化

代碼:

//MARK: UIContentContainer

override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator){

super.willTransition(to: newCollection, with: coordinator)

coordinator.animateAlongsideTransition(in: self.view, animation: { (context) in

//動畫,隨便寫點啥把.

self.btn.titleLabel?.text = "gugu"

}) { (context) in

//iphone 橫屏

if newCollection.horizontalSizeClass == .compact &&? newCollection.verticalSizeClass == .compact{

print("iphone目前是橫屏")

}

else if (newCollection.horizontalSizeClass == .compact &&? newCollection.verticalSizeClass == .regular){

print("iphone目前是豎屏")

}

}

}


3. 3D touch和trait的關系

啰嗦一點,ios9中,在ViewController中判斷設備是否支持3Dtouch.就是這么寫的:

if(self.traitCollection.forceTouchCapability ==UIForceTouchCapabilityAvailable){

[self registerForPreviewingWithDelegate:self sourceView:self.view];

}

也是用到了trait的屬性哇.

要檢測3D touch是否被用戶關閉/打開了,也是在前面提到的函數(shù)里:

traitCollectionDidChange:

4. 不同的size class對應不同的圖片尺寸

在橫屏,豎屏,以及各種寬高的size class組合下,一張圖片需要有不同的尺寸.

這個要是自己用代碼寫,會多么惡心,要適配多少情況啊,幸好image asset功能之一就是干這個事情的,后面的譯文會講到這個,image asset有配置,可以對不同的size clas配置不同的圖片,見圖13-2

5. ViewController的present關系用到的size class的改變

這就是我掉坑的重點,了解了何為size class后,vc間的present關系中,presented viewController會在不同的設備環(huán)境下有不同的表現(xiàn). 如在regular環(huán)境下(ipad)的popover窗體,到了compact環(huán)境下,會變成全屏,而我們可以通過 UIViewController的屬性:popoverPresentationController來自定義presented viewController的變現(xiàn),讓它保持非全屏的模式.


譯文-終于開始翻譯了


原文地址:https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/BuildinganAdaptiveInterface.html

一個可適應的界面應該同時響應trait和size的改變.在view controller這個層級上,用trait來大體決定你要顯示的內(nèi)容和控件們用到的layout. 例如:當在size class之間切換時,你會改變view的屬性,顯示或者隱藏一些view.

適應trait的改變


trait可讓你在不同環(huán)境下配置不一樣的app顯示,大多數(shù)配置可以在storyboard上進行,少數(shù)還需要代碼協(xié)助.

用storyboard來配置不同的Size Classes


在IB上使用size classes是很簡單的,storyboard編輯器支持在不同的size classes上顯示界面.我們可以在特定的size classes上去掉某些view或者更改layout約束,你還可以創(chuàng)建image assets,把不同的image放在不同的size classes上.這樣,你就不用用好幾套代碼來做這種適配屏幕尺寸的事了,當app的size class變化時,UIKit會自動更新對應的界面.(很cool!)

ps:官網(wǎng)上了個老圖,為了與時俱進,上最新xcode8的界面


13-1

下面那一排設備,就是不同的size classes,是蘋果所有的設備尺寸,還可以選擇橫屏和豎屏

note: 沒安裝的view還是在你的view樹里面,還可以被操作到,只是不顯示罷了

(ps:不是很懂,這里的安裝是啥意思?是說在size class-a下我加了個view,size class-b下我讓其不顯示,但是view還是在么?這樣的話,如果多來幾套布局,整個包不會很大嗎?嘻嘻,不過似乎也只能這樣子喲)

image assets 是個很好的存儲圖片資源的地兒,每個image asset都有一個圖片的多個版本,每個版本都有特定的配置.除了可以對普通屏和視網(wǎng)膜屏指定不同的圖片,還可以對橫屏和豎屏指定不同的圖片.只要在image asset里面配置的圖片,UIImageView能自動選擇和當前的size classes配置相符的圖片.(ps:這就是為啥image asset大行其道的原因吧,以前都是放圖在bunlde里,現(xiàn)在image asset 會保存多一張圖的多個版本,略占空間.但是打包發(fā)布到App Store上后,store會采用Slicing技術,針對不同的設備生成不同的app變種,變種的不同圖片的選擇就是根據(jù)image asset來篩選的,所以實際上用戶設備中的app是不會很大的. 參考文檔:

1. https://developer.apple.com/library/prerelease/content/documentation/IDEs/Conceptual/AppDistributionGuide/AppThinning/AppThinning.html#//apple_ref/doc/uid/TP40012582-CH35-SW3

2. https://onevcat.com/2013/06/new-in-xcode5-and-objc/

)

圖13-2展示了image asset的配置,因為又是老圖,所以上個新的,好多屬性,重要是的是那個width class和height class,通過其組合可以對應不同size classes下的圖片.下個帖子一一研究下


13-2

改變子view controller的Traits

默認情況下,子viewController繼承父viewController的traits.不過trait和size classes一樣,不能要求所有子viewController都和父viewController完全一樣.例如:可能給子viewController的顯示空間沒有那么大,所以一個普通(regular)的父viewController會給它的幾個子viewController賦值緊湊(Compact)的size classe.

在容器view controller中,對父viewController調(diào)方法:setOverrideTraitCollection:forChildViewController: 來調(diào)整子viewController的trait

代碼13-1 展示如何創(chuàng)建trait并賦值給子view controller. 這段代碼寫父viewController中并最好只能執(zhí)行一次.子view controller的trait會一直保持,不被父viewController影響,直到它從view層中刪除.

UITraitCollection*horizTrait=[UITraitCollection

traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassRegular];

UITraitCollection*vertTrait=[UITraitCollection

traitCollectionWithVerticalSizeClass:UIUserInterfaceSizeClassCompact];

UITraitCollection*childTraits=[UITraitCollection

traitCollectionWithTraitsFromCollections:@[horizTrait,vertTrait]];

[selfsetOverrideTraitCollection:childTraitsforChildViewController:self.childViewControllers[0]];

問題來啦,trait屬性挺多的,被父viewController指定的屬性會在子viewController中一直保持,那么沒有指定的屬性呢?答案是遵循自父viewController的變化,和其保持一致.

如上面這段代碼,如果父viewController的水平size class發(fā)生變化,可是子viewController還是保持Regular


讓Presented View Controllers有新的風格


知識儲備

先說在present的意思,蘋果里面:

如果一個ViewController? A present了另一個ViewController? B, 則A稱為presentingViewController, B稱為presentedViewController. 它們通過UIViewController的這2個屬性可以訪問到彼此.如圖1-2


1-2

實際上,presentedViewController是被presentingViewController retain了

ViewController之間的present關系是一種? 模態(tài) 的關系, B的view覆蓋在A的view上,用戶點不到A,只能操作B,想要關閉B,只能在B上提供按鈕或者navigation item?

在iPhone上present B后,默認情況下,B的view就由自下往上的動畫效果展示出來,覆蓋在A的view上.

?動畫效果是可以改的:presentedViewController的屬性modalTransitionStyle

view是覆蓋還是替換,還是自定義類似popover的局部的顯示??

用presentedViewController的屬性modalPresentationStyle來配置.這里說下:

.FullScreen

默認的機制,presentedViewController的view全屏顯示

presentingViewController還是屏幕的根viewcontroller,但是它的view直接被presentedViewController的view替換了.

.OverFullScreen

presentedViewController的view全屏顯示

presentingViewController的view還在原來的地方,只是被presentedViewController的view覆蓋了,如果presentedViewController的view設置了透明度,還能看到它在下面呢

ios8只支持.FullScreen和OverFullScreen

.PageSheet

presentedViewController的view全屏顯示

在iPad 豎屏上,它會略短一截,在statusbar的下面留出空白,ipad橫屏和iphone6 pluas上,它左右也會短一截,



present的函數(shù):

open func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (@escaping () -> Swift.Void)? = nil)

storyboard的拉線:

Present Modally 和Present as popover ,如圖1-3

1-3


關閉的函數(shù)(這么說其實不專業(yè),ios里的函數(shù)都是消息,發(fā)送給對象):

open func dismiss(animated flag: Bool, completion: (@escaping () -> Swift.Void)? = nil)

關閉時,presentingViewController收到該消息,presentedViewController的view從屏幕上撤下,不再覆蓋presentingViewController的view,然后presentedViewController的內(nèi)存被釋放. 嘻嘻!別繞暈了,很簡單的

值得一提的是:這個消息可以發(fā)送給presentingViewController也可以發(fā)送給presentedViewController. iOS的runtime會把這個消息最終傳遞到presentingViewController.所以,最終響應該消息的是presentingViewController

扯起來的話,可說的內(nèi)容還挺多的,雖然平時關閉一個vc,dismiss就萬事大吉,面試時基本也不會有人問,不過多了解一點總是好的.-_-

1. 每個presentingViewController最多只能有一個presentedViewController.如果一個presentingViewController的presentedViewController已經(jīng)不為nil了.你再給它發(fā)送present(:animated:completion:)消息,則不會發(fā)生任何反應,completion handler也不會被調(diào)用.runtime會給你個警告

2. presentedViewController也能再present view controller, 這就形成了一個鏈,如果你對中間的B發(fā)送dismiss(:completion) 消息,則C會關閉掉,B不會,因為此刻它也是一個presentingViewController ,如圖1-4


1-4

3. 如果給一個presentedViewController為nil的view controller發(fā)送dismiss(:completion) 消息,則不會發(fā)生任何事,但是completion handler會被調(diào)用

注意:

1) 默認情況下,presentedViewController覆蓋presentingViewController的全部view

1) iOS8后,無論iPhone還是iPad都可讓presentedViewController只占據(jù)presentingViewController的一個subview的空間,而不是整個view區(qū)域

2) IOS7后,無論iPhone還是iPad都可讓presentedViewController只占據(jù)presentingViewController的一部分區(qū)域,而不是整個view區(qū)域


繼續(xù)翻譯

presentedViewController 會自適應水平方向上的的regular和compact.比如:當從水平的regular變成水平的compact時,UIKit默認自動把ViewController的presentation style變成了UIModalPresentationFullScreen,自定義presentation style是由presentation controller進行調(diào)整的.

啰嗦幾句:

presentation controller和presentation style是啥呢?

UIViewController有個擴展,寫了2個只能get的屬性:

1) presentationController

2) popoverPresentationController? (它其實繼承于presentationController,是presentationController的popover的擴展)

它們不是繼承于UIViewController的,而是繼承于NSObject的.它們負責管理一個UIViewController的present的某些屬性.

注意:

一定要先給UIViewController的modalPresentationStyle屬性賦值,上面2個屬性才不會是nil的.

1) 如果modalPresentationStyle是.popover,則popoverPresentationController被賦值

2) 如果modalPresentationStyle是其他枚舉值,則presentationController被賦值

繼續(xù)翻譯

對于某些app,全屏的present會造成困擾.比如,如果點擊一個popover的bounds的外面空白地方,會關掉這個popover,但是如果這個popover已經(jīng)占領了全屏,就沒法關閉它了,就如13-3所示.如果默認的自適應style機制不能滿足你的需要,你應該告知UIKit用不同的style來present

13-3 popover從regular變成compact時,popover變成了全屏

如何自定義presenting style呢? 首先得給presentedViewController的presentationController或者popoverPresentationController設置delegate,當自適應變化開始時,delegate的方法會被觸發(fā).它會返回不同的presenting style,它還可以讓presentationController交替顯示不同的ViewController(-_- delegate略強大)

在delegate中實現(xiàn)UIAdaptivePresentationControllerDelegate的代理方法:

optional public func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle

頭文件的注釋道:在ios8里,只支持2個style

UIModalPresentationFullScreen:全屏,

UIModalPresentationOverFullScreen.

注意吧.官網(wǎng)上寫的是:adaptivePresentationStyleForPresentationController:?如果真直接copy過去實現(xiàn)這個,就完蛋了,我就栽在這里了.

代碼:

//MARK: UIPopoverPresentationControllerDelegate

func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle{

return .none

}

當app轉(zhuǎn)入compact的環(huán)境時,只支持全屏或者 無 (UIModalPresentationNone),返回.none就是告訴presentation controller忽略compact的環(huán)境,保持之前的present style,在任何設備上都如此,13-4展示了全屏和非全屏的效果,以做比較:


13-4

delegate的另一個方法

public func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController?

當進入了compact環(huán)境時,你可以在你的view層次里insert一個navigation controller,或者load一個新的view controller,來替換本該present的view controller

(不好意思,在iphone6上沒調(diào)試出來,實現(xiàn)了沒進入過該函數(shù),我還要進一步研究)


實現(xiàn)適應性彈出框(Popover)的建議


當從水平Regular變成水平Compact環(huán)境時,Pop over 需要額外的改動.水平Compact環(huán)境下,默認的行為是popover會變成全屏.因為popover的關閉方法是點擊它bounds之外的空白處,而全屏就無法做到這一點.我們可以通過下面的做法來改變這種情況:

1) 讓popover到navigation的棧里面

加一個navigation controller,通過navigationBarItem來dismiss它

2) 加控件來dismiss全屏的popover

可以通過加控件來dismiss全屏的popover,但是更多的辦法是用navigation controller換掉popover, 函數(shù)是:

presentationController:viewControllerForAdaptivePresentationStyle:

用navigation controller給你的模態(tài)界面加上一個Done按鈕或者其他控件來dismiss掉這個界面.

3) 用presentation controller的delegate消滅一切系統(tǒng)的的自適應

這就是網(wǎng)上大多數(shù)的帖子做法,他們經(jīng)常通過簡潔的方式,直接指導你實現(xiàn)步驟,但是不說為啥,對看帖子的人來說,提升不大,換而言之,看的人應該多思考多查閱,不能讓別人把什么都擺在你面前,那也做不到.除非是時間來不及,項目逼死人.--說給自己聽的!自勉!

作為popover的UIViewController,設置它的屬性popoverPresentationController的delegate

實現(xiàn)delegate的func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle方法,返回:UIModalPresentationNone (.none) 更多的信息,請參考:https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/BuildinganAdaptiveInterface.html#//apple_ref/doc/uid/TP40007457-CH32-SW6

對Size 的變化做出反應

size會因為很多原因發(fā)生變化,包括下面的:

1) 窗口的尺寸變化,大多數(shù)時候由轉(zhuǎn)動屏幕引起

2) 父view controller 重新設置了子view controller的尺寸

3) presentationController改變了它顯示的ViewController的尺寸

當size發(fā)生變化時,UIKit根據(jù)layout的約束,自動改變當前顯示的view controller層級的的尺寸和位置,如果你使用auto layout來指定view的size和位置,你的app會自動適應任何size和設備帶來的變化.

如果你的autoulayout 還不足以達到你所想要的效果, 你可以用viewWillTransitionToSize:withTransitionCoordinator: 來改變你的布局,你可以創(chuàng)建額外的動畫,這些動畫會和size-change的動畫一起運行.例如:當轉(zhuǎn)屏時,調(diào)用UIViewControllerTransitionCoordinator的屬性targetTransform?來創(chuàng)建一個反轉(zhuǎn)矩陣給某些需要的顯示控件使用


demo:https://github.com/ivychenyucong/TestPopover

參考: http://www.cnblogs.com/zhw511006/p/3998534.html ? 對ios8的size classes講解的很清楚到位

https://onevcat.com/2014/07/ios-ui-unique/ ?size class的解釋很清楚

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容