UIViewController(六):自適應和尺寸的變化

自適應界面能夠充分利用屏幕的可用空間疯潭,適應性意味著能夠調(diào)整內(nèi)容以便其能夠適合任何iOS設備嘱根。iOS中的自適應模式支持以簡單但是動態(tài)的方式來重新排列和調(diào)整內(nèi)容嚣潜,以響應更改。當使用這種模式時世囊,一個應用程序只需要很少的額外代碼就可以適應不同的屏幕尺寸(如圖12-1所示)别瞭。

圖12-1

Auto Layout是構建自適應界面的重要工具。使用Auto Layout株憾,我們可以定義管理視圖控制器視圖布局的規(guī)則(稱為約束)蝙寨。可以在Interface Builder中以可視化方式創(chuàng)建約束嗤瞎,也可以在代碼中編程創(chuàng)建約束墙歪。當父視圖的尺寸發(fā)生變化時,iOS系統(tǒng)將根據(jù)我們指定的約束條件自動調(diào)整視圖的尺寸并重新定位其余視圖贝奇。

特征(trait)是自適應模式的另一個重要組成部分虹菲。特征描述了視圖控制器和視圖必須運行的環(huán)境,特征可以幫助我們做出關于界面的高層決策掉瞳。

特征的作用

當約束不足以管理布局時毕源,視圖控制器有幾個機會去進行更改。視圖控制器陕习、視圖和一些其他對象管理著一個特征集合霎褐,這些特征指定了與該對象關聯(lián)的當前環(huán)境。下表描述了這些特征以及如何使用它們來影響用戶界面该镣。

特征 示例 描述
horizontalSizeClass UIUserInterfaceSizeClassCompact 此特征表達了界面的一般寬度冻璃。使用它來做出粗略的布局決策,例如視圖是垂直堆疊损合、并排顯示省艳、全部隱藏還是以其他方法顯示。
verticalSizeClass UIUserInterfaceSizeClassRegular 此特征表達了界面的一般高度嫁审。如果界面設計要求所有內(nèi)容都適配在屏幕上而不滾動跋炕,請使用此特征來作出布局決策。
displayScale 2.0 此特征表達內(nèi)容是顯示在Retina顯示屏上還是標準分辨率顯示屏上土居。使用它(根據(jù)需要)來做出像素級布局決策或者選擇要顯示的圖像版本。
userInterfaceIdiom UIUserInterfaceIdiomPhone 此特征提供了向后兼容性,并表達了運行應用程序的設備類型擦耀。盡可能避免使用這個特征棉圈。對于布局決策,請改為使用horizontal 和 vertical size classes 代替眷蜓。

使用特征來做出關于如何呈現(xiàn)用戶界面的決策分瘾。在Interface Builder中構建界面時,使用特征來更改顯示的視圖和圖像吁系,或者使用特征來應用不同的約束集合德召。許多UIKit類(如UIImageAsset)使用指定的特征來裁剪它們提供的信息。

以下是一些提示汽纤,可以幫助我們了解何時使用不同類型的特征:

  • 使用size class對界面進行粗略更改上岗。size class更改是一個添加或刪除視圖,添加或刪除子視圖控制器或更改布局約束的合適時機蕴坪。我們也可以不做任何事情肴掷,并讓界面使用其現(xiàn)有布局約束去自動適應。
  • 切勿假設size class與視圖的特定寬度或高度相符合背传。視圖控制器的size class可能會因多種原因而發(fā)生更改呆瞻。例如,iPhone上的容器視圖控制器可能會使其某個子視圖控制器在水平方向上固定來強制其以不同方式顯示其內(nèi)容径玖。
  • 使用Interface Builder為每個size class指定不同的布局約束痴脾。使用Interface Builder來指定約束比編程添加和移除約束要簡單得多。視圖控制器通過應用其storyboard的對應的約束來自動處理size class更改梳星。
  • 避免使用idiom信息來做出關于界面布局或界面內(nèi)容的決策赞赖。在iPad和iPhone上運行的應用程序通常應顯示相同的信息,并應該使用size class來進行布局決策丰泊。

特征和尺寸的改變會在何時發(fā)生?

特征的改變很少發(fā)生薯定,但確實會發(fā)生。UIKit根據(jù)底層環(huán)境的變化來更新視圖控制器的特征瞳购,size class特征比display scale特征更可能發(fā)生改變话侄,idiom特征很少會改變。size class會由于以下原因而發(fā)生改變:

  • 通常情況下学赛,由于設備的旋轉(zhuǎn)年堆,視圖控制器窗口的垂直或者水平size class發(fā)生改變。
  • 容器視圖控制器的垂直或者水平size class已改變盏浇。
  • 當前視圖控制器的垂直或者水平size class由其容器顯式更改变丧。

視圖控制器層次結構中的size class更改會傳遞到任何子視圖控制器。window對象作為該層次結構的最底層绢掰,為其根視圖控制器提供baseline size class特征痒蓬。當設備方向在縱向和橫向之間變化時童擎,window會更新其自己的size class信息并沿著視圖控制器層次結構傳遞該信息。容器視圖控制器可以將size class更改傳遞給未經(jīng)修改的子視圖控制器攻晒,也可以覆蓋每個子視圖控制器的特征顾复。

在iOS 8以上系統(tǒng)版本中,window的原點(origin)始終位于左上角鲁捏,當設備在橫向和縱向之間旋轉(zhuǎn)時芯砸,window的bounds會發(fā)生改變。window的尺寸的變化會與任何相應的特征變化一起沿著視圖控制器層次結構向下傳遞给梅。對于層次結構中的每個視圖控制器假丧,UIKit會調(diào)用以下方法來報告這些更改:

  • willTransitionToTraitCollection:withTransitionCoordinator:方法告知每個相關的視圖控制器其特征即將改變。
  • viewWillTransitionToSize:withTransitionCoordinator:方法告知每個相關的視圖控制器其尺寸即將改變动羽。
  • traitCollectionDidChange:方法告知每個相關的視圖控制器包帚,其特征現(xiàn)在已經(jīng)改變了。

在沿著視圖控制器層次結構傳遞信息時曹质,UIKit僅在有變化需要告知時才將變化告知給視圖控制器婴噩。如果容器視圖控制器覆蓋了其子視圖控制器的size class,則當容器的size class改變時羽德,不會告知其子視圖控制器几莽。同樣,如果視圖控制器的視圖具有固定的高度和寬度宅静,它也不會收到尺寸改變通知章蚣。

圖12-2顯示了在iPhone 6上發(fā)生旋轉(zhuǎn)時視圖控制器的特征和視圖尺寸是如何更新的。從縱向到橫向的旋轉(zhuǎn)將屏幕的垂直size class從常規(guī)變?yōu)榫o湊姨夹。size class更改后纤垂,相應視圖的尺寸也更改,然后沿著視圖控制器層次結構傳遞這些更改磷账。將視圖動畫為新尺寸后峭沦,UIKit在調(diào)用視圖控制器的traitCollectionDidChange:方法之前會應用size class和視圖尺寸的更改。

圖12-2

不同設備的默認size class

每個iOS設備都有一組默認的size class逃糟,我們可以在設計界面時作為指導吼鱼。下表列出了設備在縱向和橫向上的size class,未列在表格中的設備與具有相同屏幕尺寸的設備具有相同的size class绰咽。

設備 縱向 橫向
iPad(all)
iPad Mini
Vertical size class: Regular
Horizontal size class: Regular
Vertical size class: Regular
Horizontal size class: Regular
iPhone 6 Plus Vertical size class: Regular
Horizontal size class: Compact
Vertical size class: Compact
Horizontal size class: Regular
iPhone 6 Vertical size class: Regular
Horizontal size class: Compact
Vertical size class: Compact
Horizontal size class: Compact
iPhone 5s
iPhone 5c
iPhone 5
Vertical size class: Regular
Horizontal size class: Compact
Vertical size class: Compact
Horizontal size class: Compact
iPhone 4s Vertical size class: Regular
Horizontal size class: Compact
Vertical size class: Compact
Horizontal size class: Compact

重要:切勿假設應用程序以特定的size class在設備上顯示菇肃。在決定如何配置某個對象時,應始終檢查從該對象的特征集合中得到的size class取募。

構建一個自適應界面

自適應界面應該對特征和尺寸的改變做出響應琐谤。在視圖控制器級別,可以使用特征對顯示的內(nèi)容和該內(nèi)容的布局進行粗略的確定玩敏。例如斗忌,在不同的size class之間切換時质礼,可以選擇更改視圖屬性,顯示或者隱藏視圖织阳,或者顯示完全不同的視圖集几苍。做出這些重大決策之后,可以選擇使用尺寸更改來微調(diào)內(nèi)容陈哑。

適應特征變化

特征為我們提供了一種在不同環(huán)境下配置應用程序使其有所不同的方式,我們可以使用它對界面進行粗略調(diào)整伸眶。對特征所做的大部分更改都可以直接在storyboard中完成惊窖,但有一些還需要額外的代碼。

配置storyboard以處理不同的size class

Interface Builder使我們可以輕松地將界面調(diào)整到不同的size class厘贼。storyboard編輯器支持配置不同size class的顯示界面界酒、在指定配置中刪除視圖以及指定不同的布局約束。 使用這些工具意味著不必在運行時以編程方式進行相同的更改嘴秸。相反毁欣,UIKit會在當前size class更改時自動更新界面。

圖13-1顯示了用于在Interface Builder中配置界面的工具岳掐。size class查看控件改變了界面的外觀凭疮。使用該控件查看給定size class的界面的外觀。對于單個視圖串述,使用安裝控件來查看對于給定的size class配置是否存在視圖执解。使用復選框左側的加號(+)按鈕添加新配置。

圖13-1

image asset是存儲應用程序圖片資源的首選方式纲酗。每個image asset包含同一圖像的多個版本衰腌,每個版本均為特定配置而設計。除了為標準分辨率顯示屏和Retina顯示屏指定不同的圖像外觅赊,還可以為不同的水平和垂直size class指定不同的圖像右蕊。使用image asset進行配置時,UIImageView對象會自動選擇與當前size class和分辨率相關聯(lián)的圖像吮螺。

圖13-2顯示了image asset的屬性饶囚。更改寬度個高度屬性為目錄中的更多圖像添加插槽。用這些圖像填充這些插槽以用于每種size class組合规脸。

圖13-2

更改子視圖控制器的特征

子視圖控制器默認繼承父視圖控制器的特征坯约。對于size class特征,每個子視圖控制器都可能沒有與其父視圖控制器相同的特征莫鸭。例如闹丐,常規(guī)環(huán)境中的視圖控制器可能想要為其一個或者多個子視圖控制器配置一個緊湊的size class,來反映該子視圖控制器的空間減小被因。在實現(xiàn)容器視圖控制器時卿拴,可以通過調(diào)用容器視圖控制器的setOverrideTraitCollection:forChildViewController:來修改子視圖控制器的特征衫仑。

以下代碼顯示了如何創(chuàng)建一組新特征并將他們與子視圖控制器關聯(lián)。只需在父視圖控制器執(zhí)行這段代碼一次堕花。

UITraitCollection* horizTrait = [UITraitCollection traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassRegular];

UITraitCollection* vertTrait = [UITraitCollection
traitCollectionWithVerticalSizeClass:UIUserInterfaceSizeClassCompact];

UITraitCollection* childTraits = [UITraitCollection
traitCollectionWithTraitsFromCollections:@[horizTrait, vertTrait]];

[self setOverrideTraitCollection:childTraits forChildViewController:self.childViewControllers[0]];

當父視圖控制器的特征改變時文狱,子視圖控制器繼承任何未由父視圖控制器明確覆蓋的特征。例如缘挽,當父視圖控制器的水平size class從常規(guī)變?yōu)榫o湊時瞄崇,上面例子中的子視圖控制器保留其常規(guī)水平size class。然而壕曼,如果displayScale特征發(fā)生改變苏研,則子視圖控制器會繼承新值。

將呈現(xiàn)的視圖控制器調(diào)整為新的樣式

呈現(xiàn)的視圖控制器可以在水平常規(guī)環(huán)境和水平緊湊環(huán)境之間自動調(diào)整腮郊。當從水平常規(guī)環(huán)境切換到水平緊湊環(huán)境時摹蘑,UIKit默認將內(nèi)置的呈現(xiàn)樣式更改為UIModalPresentationFullScreen。對于自定義呈現(xiàn)樣式轧飞,presentation controller可以確定適應行為并相應地調(diào)整呈現(xiàn)內(nèi)容衅鹿。

對于某些應用程序,適應全屏樣式可能會出現(xiàn)問題过咬。例如大渤,Popover通常是通過點擊背景調(diào)光視圖來移除的,但在Popover覆蓋整個屏幕的緊湊環(huán)境中這樣做是不可能的掸绞,如圖13-3所示兼犯。當默認的自適應樣式不合適時,我們可以告訴UIKit使用不同的樣式或呈現(xiàn)一個更適合全屏樣式的完全不同的視圖控制器集漾。

圖13-3

要更改呈現(xiàn)樣式的默認自適應行為切黔,請分配一個委托對象給關聯(lián)的presentation controller。訪問呈現(xiàn)的視圖控制器的presentationController屬性來獲取presentation controller具篇。在進行任何與適應性相關的更改之前纬霞,presentation controller都會詢問委托對象。委托對象可以返回與默認不容的呈現(xiàn)樣式驱显,并且可以為presentation controller提供可選的視圖控制器以進行顯示诗芜。

使用委托對象的adaptivePresentationStyleForPresentationController:方法來指定與默認不同的呈現(xiàn)樣式。切換到緊湊環(huán)境時埃疫,唯一支持的樣式是兩種全屏樣式或者UIModalPresentationNone伏恐。返回UIModalPresentationNone會通知presentation controller忽略緊湊環(huán)境并繼續(xù)使用先前的呈現(xiàn)樣式。在呈現(xiàn)Popover時栓霜,忽略更改會為所有設備提供與iPad類似的彈出式行為翠桦。圖13-4顯示了默認的全屏適應并且沒有并排適應,可以比較下結果。

圖13-4

要完全替換視圖控制器销凑,請實現(xiàn)委托對象的presentationController:viewControllerForAdaptivePresentationStyle:方法丛晌。在適應緊湊型環(huán)境時,可以使用該方法將導航控制器插入視圖層次結構中斗幼,或者加載專門為較小控件設計的視圖控制器澎蛛。

實現(xiàn)自適應Popover的技巧

從水平正常環(huán)境切換到水平緊湊環(huán)境時,Popover需要額外的修改蜕窿。水平緊湊環(huán)境的默認行為會將Popover改為全屏呈現(xiàn)谋逻。因為通常情況下,Popover是通過點擊其背景調(diào)光視圖來被移除的桐经,改為全屏呈現(xiàn)就廢除了移除Popover的主要方式斤贰。可以通過執(zhí)行以下任一操作來補償該行為:

  • 將Popover的視圖控制器推入到現(xiàn)有導航堆棧上次询。當有父導航控制器可用時,請移除Popover并將其視圖控制器推入導航堆棧瓷叫。
  • 添加控件以在全屏呈現(xiàn)時移除Popover屯吊。可以將控件添加到Popover的視圖控制器摹菠,但更好的選擇是使用presentationController:viewControllerForAdaptivePresentationStyle:方法為導航控制器換掉Popover盒卸。使用導航控制器提供了一個模態(tài)界面和添加完成按鈕或者其他控件(用來移除內(nèi)容)的空間。
  • 使用presentation controller的委托對象去廢除任何適應性更改次氨。獲取Popover presentation controller并為其分配一個實現(xiàn)了adaptivePresentationStyleForPresentationController:方法的委托對象蔽介。從該方法返回UIModalPresentationNone會導致Popover繼續(xù)使用之前的呈現(xiàn)樣式。

響應尺寸更改

尺寸更改的發(fā)生有很多原因煮寡,包括以下:

  • 底層window的尺寸發(fā)生變化虹蓄,通常是由于設備方向改變。
  • 父視圖控制器調(diào)整其子視圖控制器的尺寸幸撕。
  • presentation controller更改其呈現(xiàn)的視圖控制器的尺寸薇组。

當尺寸發(fā)生改變時,UIKit會通過正常的布局過程自動更新可見的視圖控制器層次結構的尺寸和位置坐儿。如果使用Auto Layout約束來指定視圖的尺寸和位置律胀,則應用程序會自動適應任何更改并且應該在不同屏幕尺寸的設備上運行。

如果Auto Layout約束無法實現(xiàn)所需的外觀貌矿,則可以使用viewWillTransitionToSize:withTransitionCoordinator方法來更改布局炭菌。還可以使用該方法創(chuàng)建其他動畫與尺寸更改動畫一起運行。例如逛漫,在界面旋轉(zhuǎn)期間黑低,可以使用轉(zhuǎn)場動畫協(xié)調(diào)器的targetTransform屬性為界面的某些部分創(chuàng)建反向旋轉(zhuǎn)矩陣。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末酌毡,一起剝皮案震驚了整個濱河市投储,隨后出現(xiàn)的幾起案子第练,更是在濱河造成了極大的恐慌,老刑警劉巖玛荞,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件娇掏,死亡現(xiàn)場離奇詭異,居然都是意外死亡勋眯,警方通過查閱死者的電腦和手機婴梧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來客蹋,“玉大人塞蹭,你說我怎么就攤上這事⊙扰鳎” “怎么了番电?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長辆琅。 經(jīng)常有香客問我漱办,道長,這世上最難降的妖魔是什么婉烟? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任娩井,我火速辦了婚禮,結果婚禮上似袁,老公的妹妹穿的比我還像新娘洞辣。我一直安慰自己,他們只是感情好昙衅,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布扬霜。 她就那樣靜靜地躺著,像睡著了一般而涉。 火紅的嫁衣襯著肌膚如雪畜挥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天婴谱,我揣著相機與錄音蟹但,去河邊找鬼。 笑死谭羔,一個胖子當著我的面吹牛华糖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播瘟裸,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼客叉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起兼搏,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤卵慰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后佛呻,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體裳朋,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年吓著,在試婚紗的時候發(fā)現(xiàn)自己被綠了鲤嫡。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡绑莺,死狀恐怖暖眼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情纺裁,我是刑警寧澤诫肠,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站欺缘,受9級特大地震影響栋豫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜浪南,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望漱受。 院中可真熱鬧络凿,春花似錦、人聲如沸昂羡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽虐先。三九已至怨愤,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蛹批,已是汗流浹背撰洗。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留腐芍,地道東北人差导。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像猪勇,于是被迫代替她去往敵國和親设褐。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內(nèi)容