iPhone自誕生以來,隨着其屏幕尺寸不斷的多樣化,屏幕適配的技術一直在發展更新。目前,iOS系統版本已經更新到9.3,XCode的最新版本已是7.3,僅iPhone歷史產品的尺寸就已經有4種:3.5英寸、4.0英寸、4.7英寸、5.5英寸。最近,iPhone家族又誕生一款iPhoneSE,鑑於這款iPhoneSE的屏幕尺寸和iPhone5S的尺寸如出一轍——一樣是4.0英寸,廣大iOS開發者可算是鬆了口氣,否則iOS的屏幕尺寸真的是愈來愈讓人眼花繚亂。
按照時間順序,屏幕適配是這樣發展的:純代碼計算frame-> autoresizing(早期進行UI佈局的技術,僅適用於約束父子控件之間的關係)->AutoLayout(iOS6/2012年、iPhone5被引入,比autoresizing更加高級,旨在替代autoresizing,能夠設置任何控件之間的關係)->sizeClass(iOS8出現,用於解決愈來愈多的屏幕尺寸的適配問題)。
在iPhone3gs時代,手機的屏幕尺寸有且只有一種,也就是3.5英寸。開發app的時候,根本不用考慮同一個視圖在不一樣尺寸的屏幕上顯示的問題。iOS開發者徹底能夠用純代碼的方式把一個控件的frame寫死。
後來apple公司推出了4.0英寸的iPhone5和iPhone5S,因此,針對於不一樣尺寸的屏幕,再把控件的frame寫死就不可取了。(其實也不是不可取,不少iOS開發者作屏幕適配的時候不是用的autoresizing或autolayout,而是以代碼的方式動態獲取屏幕的尺寸,而後根據屏幕的尺寸來寫死子控件的frame。使用這種方式你會在代碼中無辜增長不少if...else... 的條件判斷語句。另外一種方式是獲取到屏幕的尺寸後,按照控件和屏幕的比例來設置控件的frame,其本質上也是寫死frame。因此這兩種方式都不可取,畢竟未來會回出現愈來愈多的屏幕尺寸。從開發的角度,重複繁瑣的代碼會牽絆住開發者的進度;從程序設計角度,這樣的設計思路不夠高級,且往後不易於拓展和維護。)程序員
iOS屏幕適配主要有三個技術,分別是Autoresizing、AutoLayout、SizeClass。利用純代碼計算視圖的frame咱們在此就很少介紹。至於什麼是Autoresizing?什麼是AutoLayout?什麼是SizeClass?咱們用SToryBoard的一張截圖能夠說明問題,以下圖。編程
Autoresizing和Auto Layout不能共存,因此若是使用Autoresizing,就不能勾選Use Auto Layout。xcode
Autoresizing是早期iOS設備機型不多、APP界面佈局相對簡單的背景下產生的一種屏幕適配技術。早期的iOS設備機型不多、屏幕尺寸單1、APP界面相對簡單,屏幕適配並無如今這麼複雜,在當時這種背景下,產生了Autoresizing。當時這種狀況下蘋果推出Autoresizing也是能夠理解的,可是若是放到如今這種大背景下,Autoresizing是不可以知足開發者的屏幕適配需求的,具體緣由請見下文。markdown
Xcode5以後,新建的項目默認使用AutoLayout。Autoresizing默認不啓用,咱們能夠去掉use Auto Layout前面的對勾來啓用Autoresizing,以下圖。app
有一種說法:autoresizing是爲了解決iPad開發中橫豎屏適配問題應運而生的。代碼中的autoresizingMask和storyBoard中尺寸檢查器中的Autoresizing是一回事。iPhone5開始,Xcode添加了autolayout功能。storyBoard默認採用autolayout,取代了以前的autoresizing。若是使用autoresizing,須要在如下位置去掉「Use Auto Layout」。框架
從上圖看出,storyBoard中的的Autoresizing只能設置兩個父子視圖之間的相對位置關係,一共6條虛線,分別是周圍的四條虛線和方塊內部的兩條線。周圍的四條虛線分別表明子控件距離父控件上、下、左、右之間的距離關係/或者叫約束關係,周圍的四條虛線所包圍的小方塊表明子視圖,小方塊內部的兩條帶雙向箭頭的線分別表明子控件的寬度和高度。
當咱們點擊周圍四條虛線時,虛線會變成實線,表明子控件和父控件在這個方向上的間距被固定了。當咱們點擊子視圖內部的虛線時,一樣也變爲實線,表明子視圖的寬度或者高度被固定了。
舉個例子:當咱們點擊最左邊的虛線時候,表明子視圖距離父視圖左邊的間距被固定了,而其餘三個方向的距離和寬高會隨父視圖的縮放二縮放。iphone
咱們不只能夠在storyboard中使用Autoresizing來約束父子視圖,也可使用代碼來設置父子視圖之間的位置關係。UIView有一個autoresizingMask屬性,能夠經過該屬性來約束父子視圖以前的位置關係,而且UIView還有一個BOOL類型的autoresizesSubviews屬性,默認爲YES,表明父控件會跟隨子控件尺寸的變化而變化。和frame、bounds、center、transform等屬性同樣,autoresizingMask和autoresizesSubviews也是屬於UIView的幾何分類-UIViewGeometry中的屬性。ide
@property(nonatomic) BOOL autoresizesSubviews; // default is YES. if set, subviews are adjusted according to their autoresizingMask if self.bounds changes @property(nonatomic) UIViewAutoresizing autoresizingMask; // simple resize. default is UIViewAutoresizingNone
查看註釋,autoresizesSubviews屬性的大意是:默認autoresizesSubviews = YES。若是UIView設置了autoresizesSubviews,那麼他的子控件的bounds若是發生了變化,他的子控件將會根據子控件本身的autoresizingMask屬性的值來進行調整。
那麼autoresizingMask又是什麼呢?
autoresizingMask是一個枚舉值,做用是自動調整子控件與父控件中間的margin(間距)或者子控件的寬高。默認其枚舉值是UIViewAutoresizingNone。以下是其所有的枚舉值:工具
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
UIViewAutoresizingNone = 0, UIViewAutoresizingFlexibleLeftMargin = 1 << 0, UIViewAutoresizingFlexibleWidth = 1 << 1, UIViewAutoresizingFlexibleRightMargin = 1 << 2, UIViewAutoresizingFlexibleTopMargin = 1 << 3, UIViewAutoresizingFlexibleHeight = 1 << 4, UIViewAutoresizingFlexibleBottomMargin = 1 << 5 };
從上面給出的代碼能夠看出,autoresizingMask有7個枚舉值,除了UIViewAutoresizingNone以外還有6個枚舉值,分別對應storyboard中的那6條虛線。因此,storyboard和代碼是相同的,不管什麼視圖,凡是能夠經過storyboard進行設置的屬性,都有與之對應的屬性代碼,咱們也可使用代碼的方式實現。畢竟,storyboard中的屬性最終仍是會翻譯成可執行的代碼,只不過XCode利用可視化的storyboard工具幫助咱們完成了代碼完成的事情。
值得注意的是:autoresizingMask的枚舉值是使用位移的形式給出的,這樣設置的好處在於,當咱們使用代碼給某個視圖設置autoresizingMask屬性時,咱們能夠給autoresizingMask屬性指定多個枚舉值。指定方式以下:oop
[subView setAutoresizingMask:UIViewAutoresizingFlexibleRightMargin |
![7.gif](//upload-images.jianshu.io/upload_images/1055199-b48a0ccf7076c294.gif?imageMogr2/auto-orient/strip) FlexibleLeftMargin];
甚至咱們可使用這種方式:
[subView setAutoresizingMask:5];
系統自動把5分解成5 = 4 + 1。而後咱們就能夠知道:4 = 1 << 2 = UIViewAutoresizingFlexibleRightMargin;1 = 1 << 0 = UIViewAutoresizingFlexibleLeftMargin。因此上面的代碼就被解釋成:
[subView setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin]; // 子視圖距離父視圖左右間距不變,寬度隨父視圖寬度的縮放而縮放。
不難發現,這樣以位移的方式指定autoresizingMask枚舉值,也契合了storyboard中能夠給子控件設置多個方向的約束的情景。以下圖:
注意:
Autoresizing只能設置父子視圖之間的關係,也就是說,Autoresizing只能控制子視圖和父視圖之間的位置/大小關係。Autoresizing不能設置兄弟視圖之間的關係,固然也不能設置徹底不相關的兩個視圖之間的關係。正由於Autoresizing只能設置父子視圖之間的關係,因此,Autoresizing只能應用於兩個視圖之間,不能應用於三個或者更多視圖之間。畢竟,一個兒子不可能有兩個親爹。注意:
UIView的autoresizesSubviews屬性爲YES時(默認爲YES),autoresizingMask纔會生效。也就是說,當咱們想要利用autoresizingMask指定某個控件和其父控件的關係時候,必須autoresizesSubviews = YES。注意:
值得注意的是,autoresizingMask的每一個枚舉值都帶有Flexible
這個單詞,其意思是:靈活的,彈性的。因此,咱們在對其枚舉值進行一一翻譯。
UIViewAutoresizingNone // 就是不自動調整。 UIViewAutoresizingFlexibleLeftMargin // 自動彈性的調整與superView左邊的距離,保證與superView右邊的距離不變。 UIViewAutoresizingFlexibleRightMargin // 自動彈性的調整與superView的右邊距離,保證與superView左邊的距離不變。 UIViewAutoresizingFlexibleTopMargin // 自動彈性d調整與superView頂部的距離,保證與superView底部的距離不變。 UIViewAutoresizingFlexibleBottomMargin // 自動彈性的調整與superView底部的距離,也就是說,與superView頂部的距離不變。 UIViewAutoresizingFlexibleWidth // 自動彈性的調整本身的寬度,保證與superView左邊和右邊的距離不變。 UIViewAutoresizingFlexibleHeight // 自動彈性的調整本身的高度,保證與superView頂部和底部的距離不變。
看完翻譯才恍然大悟,原來這些枚舉值和storyboard中的虛線是相反的,當咱們點擊了storyboard中國的某個虛線後表明其間距被固定,而咱們用代碼設置則表明相反方向的間距被固定。
可是,例外的是,storyBoard中子控件內部的兩個帶箭頭的虛線和枚舉值UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
具備相同的意義。也就是說,當咱們點擊了storyBoard中子控件內帶箭頭的水平虛線使之變爲實線時,就至關於[subView setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
當咱們點擊了storyBoard中子控件內帶箭頭的垂直虛線使之變爲實線時,就至關於[subView setAutoresizingMask UIViewAutoresizingFlexibleHeight];
注意:
簡而言之,4條margin虛線表明設置autoresizingMask中的與之對應的4枚舉值,而實線的width和height才表明設置autoreMask中與之對應的2個枚舉值。
autoresizingMask枚舉值及其對應的storyBoard預覽效果說明
UIViewAutoresizingMaskNone
view的frame不會隨superview的改變而改變,至關於frame(右圖的xib中預覽效果與實際效果有差,實際效果是view的上邊距不變)
UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin
view和其superView左間距和上間距固定,寬高固定,右間距和底部間距隨父控件的縮放而按比例縮放
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin
view與其superView上間距固定,右間距固定,寬高固定,左間距、下間距鎖父控件的縮放而縮放
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin
view與其superView的右間距、底部間距固定,寬高固定,上間距、左間距隨父控件的縮放而縮放
UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin
view與其superView的左間距、底部間距固定,寬高固定,右間距、上間距隨父控件的縮放而縮放
UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleHeight
view與其superView的上間距、左間距、底部間距固定,寬度固定。高度、右邊距隨父控件縮放而縮放
UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth
view與其superView的左間距、上間距、右間距固定,高度固定。寬度、底部間距隨父控件的縮放而縮放
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleHeight
view與其superView的上間距、右間距、底部間距固定,寬度固定。高度、左間距隨父控件的縮放而縮放
UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth
view與其superView的左間距、右間距、底部間距固定,高度固定。寬度、上間距隨父控件的縮放而縮放
UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
view與其superView的左間距、上間距、底部間距固定。寬度、高度、右間距隨父控件的縮放而縮放
UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
view與其superView的左間距、上間距、右間距固定。寬度、高度、底部間距隨父控件的縮放而縮放
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
view與其superView的上間距、右間距、左間距固定。寬度、高度、左間距隨父控件的縮放而縮放
UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
view與其superView的左間距、底部間距、右間距固定。寬度、高度、上間距隨父控件的縮放而縮放
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottom
view與其superView的寬高比例維持不變,上下左右間距也隨其superView的縮放而縮放
UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin
view與其superView的左右間距固定,高度固定,寬度、上間距、底部間距隨其父控件的縮放而縮放
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin
view與其superView的上下左右邊距的比例維持不變,寬高固定,反映在storyBoard中,就是什麼都不設置
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin
左邊距、右邊距、寬按比例調整,上邊距固定,下邊距固定,高度固定(右圖的xib中預覽效果與實際效果有差,實際效果是view的上邊距不變)垂直方向是一樣效果,故不列舉
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight
自動調整view的寬和高,保證上下左右邊距不變。如把tableView設置爲此屬性,那麼不管viewController的view是多大,都能自動鋪滿
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin
view與其superView的左邊距和右邊距的比例維持不變,上下間距固定,寬高固定(下圖的xib中預覽效果與實際效果有差,實際效果是view的上邊距不變)這種約束方式至關於上下間距固定,寬高固定,那麼父控件高度縮放的時候就會產生衝突,因此這種佈局方式是不合理的
UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin
view與其superView的上邊距和下邊距的比例維持不變,左右間距固定,寬高固定(這種約束方式至關於左右間距固定,寬高固定,那麼父控件寬度縮放的時候就會產生衝突,因此這種佈局方式也是不合理的)
UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth
view與其superView的左邊距和width按比例調整,高度固定,右邊距固定,上邊距固定,下邊距固定(下圖的xib中預覽效果與實際效果有差,實際效果是view的上邊距不變)(這種約束方式至關於上下間距固定,高度固定,那麼父控件高度縮放的時候就會產生衝突,因此這種佈局方式也是不合理的)
綜上發現,只要是咱們在水平方向同時固定了左邊距和右邊距,那麼咱們千萬不能固定子控件的寬度(反應在storyBoard中的設置,也就是必須使控制子控件寬度的虛線變爲實線)。同理, 若是垂直方向同時固定了上邊距和下邊距,那麼咱們不能固定子控件的高度(反應在storyBoard中的設置,也就是必須使控制子控件高度的虛線變爲實線)。
注意:
若是咱們在storyBoard中選中控制器的view,而後在尺寸檢查器中查看會發現,autoresizing中控制子控件的寬度和高度的虛線自動變成了實線(然而我並無點擊),這是由於控制器的view的寬高是一個默認值,默認和屏幕的尺寸相等,因此咱們不能經過autoresizing來設置控制器的寬高。從另外一個角度也能解釋:autoresizing是約束子控件和父控件之間的位置關係的,控制器的view並無父控件,因此不能經過autoresizing來約束控制器的view。
AutoLayout的前身是Autoresizing,也就是說,AutoLayout旨在替代Autoresizing。AutoLayout自iOS6開始引入,但因爲當時XCode4當時對AutoLayout的支持不是很好,因此在XCode5/iOS7及其以後,AutoLayout纔開始被普遍應用。注意:
既然前面已經說了,AutoLayout旨在替代Autoresizing,因此在同一個項目中,AutoLayout和Autoresizing是不能共存的,兩者只能選其一,若是你選擇了AutoLayout,那麼Autoresizing自動被屏蔽掉;若是你選擇了Autoresizing,那麼AutoLayout自動被屏蔽掉。XCode5及其以後的版本,默認新建的項目就是使用AutoLayout,不過咱們能夠在項目中進行更改,以下圖。
Auto Layout is a Constraint-Based, Descriptive Layout System.
翻譯過來大意是:autolayout是一個基於約束的、描述性的佈局系統。autolayout之因此可以進行屏幕適配,是由於他和autoresizing同樣,都是對屏幕上的控件相對位置的設置,而不是絕對位置。用蘋果官方的話,Auto Layout是一個基於約束的,描述性的佈局系統。所謂基於約束就是表明咱們能夠爲須要佈局的子控件添加一些約束對象來限制他在屏幕上顯示的位置。所謂描述性是指其約束的設置可讀性較高,接近於人類語言。
1.約束 每在Storyboard中對控件添加一個約束(autolayout的約束), 就表明添加一個約束對象。好比,給storyBoard中的某個子控件A設置了寬度和高度、距離父控件上下左右之間的間距,就至關於給這個控件添加了6個約束,也就產生了6個約束對象。 2.約束錯誤(紅色箭頭) 若是看到Storyboard中有紅色的箭頭, 表明約束有錯誤 注意: 約束有錯誤, 不表明運行會錯誤, 約束有錯誤一樣能夠運行 注意: 紅色箭頭是程序員必須解決的 3.爲何會有約束錯誤? 3.1缺乏約束 3.2約束衝突 3.1缺乏約束 >autolayout的本質和frame差很少 >若是經過frame來設置一個控件, 必須設置這個控件的x/y/width/height, 控件才能按照咱們的需求顯示 >若是是經過autolayout來設置一個控件, 也必須設置這個控件的x/y/width/height, 控件才能按照咱們的需求顯示 >也就是說, 若是說x/y/wedth/height只要有一個沒有設置都會報錯, 就是缺乏約束 >由於autolayout對控件的約束是一種相對位置的約束,因此咱們能夠經過間接的方式來設置約束。好比,給某個子控件A設置了左邊距和右邊距後,雖然沒有明確指定子控件A的寬度,可是其左右邊距一旦設置,那麼寬度能夠根據子控件A和父控件左右之間的邊距自動推算出來。這就是我所說的間接的、相對位置的約束。 3.2約束衝突 >約束能夠重複添加,但容易引起約束衝突 >例如先約束某個子控件A的高度等於100,而後又給這個子控件A添加了一個高度約束, 約束高度等200, 那麼這兩個約束就產生了衝突,控件A不知道他本身的高度是100仍是200,因此就會產生約束衝突,系統就會報錯。 紅色: 距離頂部有20 == 至關於設置了Y 距離左邊有20 == 至關於設置了x 設置寬度等於100 設置高度等於100 4.約束警告 若是看到Storyboard中有黃色的箭頭, 就是警告 > 警告表明着當前控件在storyBoard中呈現的位置或者尺寸和程序運行後實際呈現的效果不同,致使約束警告的緣由每每是沒有更新控件的約束,但並不影響其真實效果,也不會報錯。 */
}
注意:
用storyBoard設置約束的時候,注意有一個Constrain to margins,默認打勾,也就是默認會給視圖添加一個20的左右邊距(上下不會添加),目的是讓視圖在iPhone6P和iPhone6SP上顯示的更好看一些。
1.兩個同層級view之間的約束關係,添加到他們共同的父view上
2.兩個不一樣層級上的view之間的約束關係,添加到他們最近的共同的父view上
3.兩個有層次關係的view之間的約束關係,添加到層次較高的view上
4.若是view的約束只和本身有關係,那麼添加到本身身上。好比寬高約束。
UILabel默認內容的顯示方式是垂直居中的。若是用autolayout給UILabel設置約束,只須要設置x、y、width,無需設置height,UILabel會自動包裹內容,而且隨內容的多小而變化。若是咱們經過約束給定了UILabel的width = 100,可是內容仍然少的可憐,不能包裹,能夠把寬度設置爲<=100,此時,label的寬高都能包裹住內容。高度的設置同理可證。
固然,咱們也能夠只給UILabel設置x、y。但必需要保證UILabel的text屬性有內容,不然UILabel顯示不出來(這是初學者常常犯的錯誤)。緣由在於,UILabel是根據內容自動調整寬度和高度,若是沒有內容,那麼寬度和高度就是0,致使UILabel沒法顯示。
若是但願父控件隨子控件(UILabel/UIView)高度的變化而變化,就不要給父控件添加高度約束,只須要子控和向父控件在垂直方向上添加約束,這樣子控件高度改變,父控件高度也會隨之改變。
事實上,咱們在xib或者StoryBoard上給控件添加的約束,也是會被翻譯成代碼執行的。那麼添加的那些約束會被翻譯成什麼呢?本質上,在xib或者StoryBoard上添加的也U樹都是NSLayoutConstraint類型的對象。能夠經過在StoryBoard上的控件和對應的.h或者.m文件之間拖線添加IBOutlet引用來證實。
#import "ViewController.h" @interface ViewController () @property (weak, nonatomic) IBOutlet NSLayoutConstraint *heightConstraint; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *topConstraint; @property (weak, nonatomic) IBOutlet UIView *customView; @end @implementation ViewController - (void)touchesBegan:(nonnull NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event { // WSLog(@"%f", self.heightConstraint.constant); self.heightConstraint.constant += 10; self.topConstraint.constant += 100; [UIView animateWithDuration:2.0 animations:^{ [self.customView layoutIfNeeded]; }]; } @end
以下圖,假設給控制器的view添加一個寬高均爲100、水平、垂直居中的控件
代碼以下:
// 1.建立控件 UIView *redView = [[UIView alloc] init]; redView.backgroundColor = [UIColor redColor]; [self.view addSubview:redView]; #warning 注意: 經過代碼給子控件添加Autolayout約束,必需要先把子控件添加到父控件身上! // 2.建立約束 #warning 注意點: 若是經過代碼來設置Autolayout約束, 那麼必須先禁用Autoresizing redView.translatesAutoresizingMaskIntoConstraints = NO; // 2.1寬度 NSLayoutConstraint *width = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:kNilOptions multiplier:1.0 constant:100.0]; // 將約束添加給本身 [redView addConstraint:width]; // 2.2高度 NSLayoutConstraint *height = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:kNilOptions multiplier:1.0 constant:100.0]; // 將約束添加給本身 [redView addConstraint:height]; // 2.3水平居中 NSLayoutConstraint *xCos = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0.0]; // 將約束添加到層次較高的父view上 [self.view addConstraint:xCos]; // 2.4垂直居中 NSLayoutConstraint *yCos = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0.0]; // 將約束添加到層次較高的父view上 [self.view addConstraint:yCos];
Masonry是目前最流行的、最經常使用的AutoLayout的第三方開源框架。Masonry採用鏈式編程思想,極大的方便了開發者。你們能夠在GitHub上找到Masonry。
一樣的問題,仍是給控制器的view添加一個寬高均爲100、水平、垂直居中的控件的Masonry的代碼,看起來就簡潔多了,Masonry代碼以下:
// 1.建立一個控件 UIView *redVeiw = [[UIView alloc] init]; redVeiw.backgroundColor = [UIColor redColor]; [self.view addSubview:redVeiw]; // 2.禁止紅色View的Autgoresizing redVeiw.translatesAutoresizingMaskIntoConstraints = NO; [redVeiw mas_makeConstraints:^(MASConstraintMaker *make) { make.width.equalTo(100); make.height.equalTo(100); make.centerX.equalTo(self.view.mas_centerX); make.centerY.equalTo(self.view.mas_centerY); }];
注意:
通常狀況下,多數使用storyBoard中的autolayout設置約束,只有在萬不得已的狀況下才用代碼設置autolayout約束,這種狀況通常是,被約束的控件是代碼建立的,或者被約束的控件的父控件是代碼建立的。
本篇文章沒有講解蘋果自家的AutoLayout語言—VFL。由於筆者對VFL不使用很少,工做中幾乎沒有用到過,因此本篇文章就略過,感興趣的讀者能夠本身研究。
以下圖,就是sizeClass:
iOS8/XCode6纔開始引入的。SizeClass依賴於AutoLayout,也就是說,若是你的項目中用到了SizeClass,那麼必需要使用AutoLayout。因此,不存在SizeClass和Autoresizing聯合使用的狀況!
確切的說,sizeClass並非一種屏幕布局技術,經過上面對autoresizing和autolayout的介紹,咱們知道了autoresizing和autolayout是對屏幕上控件的相對位置進行的設置,也就是說,autoresizing和autolayout是針對於屏幕上的子控件而產生的技術。但sizeclass是對不一樣尺寸的屏幕的區分,sizeclass把不一樣尺寸(包括橫屏和豎屏)的屏幕進行了分類,不管是iPhone仍是iPad設備,其寬度和高度都被劃分爲三種類型:compact(緊湊)、regular(正常)、any(任意)咱們只要針對於某一類型的屏幕進行佈局,那麼佈局出來的界面能夠顯示在屬於該類型的全部尺寸的屏幕上。
不少人認爲sizeclass對屏幕寬度和高度的區分分爲三種,compact(緊湊)、regular(正常)、any(任意)。這三種類型進行組合能夠有9種結果。但在我看來,sizeclass對屏幕的區分只有兩種:compact和regular。any並非真正的類型,他只是表明了compact和regular。正像runLoop中的commonMode同樣,並非一種真正的mode,只是表明了defaultMode和trackMode。
sizeClass尺寸對照:
通常狀況下,StoryBoard中的sizeclass是(any,any)的。在sizeclass爲(any,any)時佈局的控件能夠顯示在任何尺寸的設備上,包括全部尺寸的iPhone和iPad。若是咱們選擇sizeclass爲(compact,regular),那麼在storyBoard上佈局的控件只會顯示在寬度爲「緊湊」,高度爲「正常"狀態的設備上,也就是全部的「豎屏狀態」的iPhone上。橫屏狀態的iPhone不會顯示這個控件,橫屏和豎屏狀態的iPad也不會顯示這個子控件。
因此,當咱們但願某個控件在橫屏是顯示,在豎屏時不顯示的時候,能夠考慮有sizeClass這種技術。
而且,在iPad開發時,針對於同一界面,咱們一般須要對橫豎屏的iPad分別進行佈局,此時也可使用sizeClass,咱們只須要切換storyBoard底部的sizeClass就能夠佈局初互不干擾的界面。
在出現sizeClass技術以前,咱們用xcode新建的universal項目默認會有兩個storyBoard,一個是專門爲iPhone開發的storyBoard,另外一個是專門爲iPad開發的storyBoard。而在sizeClass出現以後,咱們新建的universal項目就只有一個main.storyBoard。由於經過sizeClass咱們能夠在這一個main.storyBoard上爲iPhone和iPad佈局。
前面已經說過,咱們選中sizeClass中一種屏幕類型,進行的佈局只會出如今響應的設備上。好比,我選中w Compact H Regular。也就是寬度緊湊,高度正常。那麼在這種狀態的storyBoard上佈局的控件只會出如今豎屏的iPhone設備上,不會出如今橫屏的iPhone設備上。不信你繼續往下看:
1>選中storyBoard上的sizeClass爲W Compact H Regular。下面會有提示:For all iPhone in portrait。也就是在這個狀態下佈局的控件只能出如今全部豎屏狀態的iPhone上!
2>此時會發現storyBoard上的初始化控制器由原來的正方形(W Any H Any)變爲iPhone狀態的長方形。
3>給storyBoard上的控制器添加一個水平、垂直居中、寬高都爲150的紅色button。以下圖:
4>而後咱們預覽在4英寸的iPhone設備上,橫屏和豎屏的顯示狀況,以下圖:
從上圖,你會發現,當我把iPhone切換到橫屏狀態時,本來在豎屏顯示的紅色按鈕不見了。緣由就在於,這個紅色按鈕是在sizeClass爲W Compact H Regular狀態下添加給storyBoard上這個控制器的。這也驗證了我前面說過的,sizeClass爲寬度緊湊,高度正常狀態時的佈局智慧顯示在全部豎屏的iPhone上。固然,此處,我只是拿4.0英寸iPhone舉例,其餘尺寸iPhone同理可證。在其餘尺寸(3.五、4.七、5.5英寸)的橫屏狀態也不會顯示。固然,在iPad全屏(橫屏或豎屏)狀態下一樣不會顯示。由於iPad 的屏幕尺寸根本就不在 W Compact H Regular這一列。
可是,在iPad分屏狀態下是會顯示的。
1>仍是上面的那個storyBoard,仍是上面的那個帶有紅色按鈕的控制器。咱們如今把sizeClass切換爲W Regular H Compact狀態。以下圖:
2>你會發現,在設置sizeClass爲W Regular H Compact時,下面的提示是:For 5.5-inch iphones in landscape。也就是說,在W Compact H Regular狀態下給控制器的View添加的子控件只會出如今5.5英寸的橫屏狀態下的iPhone上。同時你也會發現,在W Compact H Regular狀態下給控制器的view添加的紅色button不見了。以下圖:
3>而後咱們給控制器的view左上角(此處的左上角是相對於垂直狀態)添加一個綠色的button。以下圖:
4>而後咱們預覽在5.5英寸的iPhone設備上,橫屏和豎屏的顯示狀況,以下圖:
從上圖,你會發現,咱們在W Regular H Compact狀態下給控制器左上角添加的綠色的按鈕只會顯示在橫屏狀態下,切換到豎屏狀態後,左上角什麼都沒有。這也驗證了sizeClass爲W Regular H Compact狀態下的佈局會出如今5.5英寸的橫屏的iPhone上而不會出如今5.5英寸豎屏的iPhone上。
固然,切換到豎屏時,你一樣發現了控制器中間出現了一個紅色的按鈕,沒錯,這就是咱們在上一個例子中(W Compact H Regular狀態)設置的那個水平、垂直居中的紅色button。這也再次驗證了,咱們在不一樣的sizeClass下的佈局並不會相互影響。
咱們在W Regular H Compact狀態下的佈局不是說好了「只會」出如今5.5英寸的橫屏狀態下嗎?上面只是驗證了會出如今5.5英寸的橫屏狀態的iPhone上,可是並無驗證「只會」這個詞語。請看下圖:
上圖是以4.0英寸的iPhone設備爲例進行的驗證,你會發現,在4.0英寸的設備處於橫屏狀態時,左上角並無出現綠色的button。至此,咱們證實了sizeClass爲W Regular H Compact時,在storyBoard上的控制器上的佈局只會出如今5.5英寸的橫屏狀態的iPhone設備上。
1>仍是上面那個storyBoard,仍是上面那個控制器,咱們如今把sizeClass切換爲W Regular H Regular,你會發現下面的提示:For iPads in portrait or landscape。也就是說,在sizeClass爲W Regular H Regular狀態下的佈局只會出如今全部橫屏或豎屏的iPad設備上,並不會出如今橫屏或者豎屏的iPhone設備上。
2>和上面那個例子同樣,咱們切換了sizeClass後,storyBoard上的控制器也變了形狀--變成了和iPad同樣方方正正的一個控制器。而且在左上角綠色的button不見了。"好像"變成了一個乾乾淨淨的控制器。
3>而後給控制器的右上角添加一個藍色的button,以下圖:
4> 而後咱們預覽在iPad和iPhone設備上橫豎屏的顯示狀況,以下圖:
從上圖,能夠看出,在iPhone上不管是橫屏仍是豎屏,右上角都沒有顯示那個藍色的button。綜上,驗證了sizeClass爲W Regular H Regular狀態時,在控制器上的佈局只會顯示在iPad橫屏或者豎屏狀態下,而不會顯示在iPhone的橫屏或者豎屏狀態下。
上面我列舉了三種sizeClass狀態下佈局顯示狀況,而按照sizeClass的九宮格組合狀況來看,sizeClass應該有9個不一樣的組合。固然any表明了compact和regular(正常和緊湊)。好比,當咱們選擇sizeClass爲 W Regular H Any(寬度正常 高度任意)時,其實這表明了兩個不一樣的sizeClass:W Regular H Regular (寬度正常 高度正常)和 W Regular H Compact(寬度正常 高度緊湊)。也就是說,在sizeClass爲 W Regular H Any(寬度正常 高度任意)狀態下的佈局至關於在sizeClass爲 W Regular H Regular(寬度正常 高度正常) 和W Regular H Compact(寬度正常 高度緊湊)佈局之和。換句話說,在sizeClass爲W Regular H Any(寬度正常 高度任意)下的佈局的控件,無論高度如何,只要寬度正常就會顯示出來。
未完待續...
文/VV木公子(簡書做者)
PS:如非特別說明,全部文章均爲原創做品,著做權歸做者全部,轉載轉載請聯繫做者得到受權,並註明出處,全部打賞均歸本人全部!
若是您是iOS開發者,或者對本篇文章感興趣,請關注本人,後續會更新更多相關文章!敬請期待!