AutoLayout簡(jiǎn)介
AutoLayout旨在替代Autoresizing,所以在同一個(gè)項(xiàng)目中,AutoLayout和Autoresizing是不能共存的,二者只能選其一,如果你選擇了AutoLayout,那么Autoresizing自動(dòng)被屏蔽掉;如果你選擇了Autoresizing,那么AutoLayout自動(dòng)被屏蔽掉。XCode5及其之后的版本,默認(rèn)新建的項(xiàng)目就是使用AutoLayout
關(guān)于約束
約束概念
AutoLayout主要是通過控件參照與約束實(shí)現(xiàn),比如控件A相對(duì)控件B來說,控件A在控件B的正下方,間距為20px
每在xib或sb中對(duì)控件添加一個(gè)約束, 就代表添加一個(gè)約束對(duì)象。比如,給xib中的某個(gè)子控件A設(shè)置了寬度和高度、距離父控件上下左右之間的間距,就相當(dāng)于給這個(gè)控件添加了6個(gè)約束,也就產(chǎn)生了6個(gè)約束對(duì)象
約束錯(cuò)誤警告
- 紅色箭頭,代表約束錯(cuò)誤,一般是缺少約束或約束沖突(例如375的屏幕寬度,你不能距離左邊200,距離右邊200,還要控件寬度100,肯定不行)
- 黃色箭頭,代表約束警告,表示當(dāng)前控件在xib中呈現(xiàn)的位置或者尺寸和程序運(yùn)行后實(shí)際呈現(xiàn)的效果不一樣,導(dǎo)致約束警告的原因往往是沒有更新控件的約束,但并不影響其真實(shí)效果,也不會(huì)報(bào)錯(cuò)
注意:約束有錯(cuò)誤,不代表運(yùn)行會(huì)錯(cuò)誤,約束錯(cuò)誤同樣可以運(yùn)行
約束的規(guī)則
- 相對(duì)于父視圖的約束,添加到父視圖上

-
相對(duì)于另一個(gè)控件的約束,添加到其共有的父視圖上
對(duì)于兩個(gè)不同層級(jí) view 之間的約束關(guān)系,添加到他們最近的共同父 view 上 -
跨層級(jí)的約束,添加到其最上層的父視圖上
對(duì)于有層次關(guān)系的兩個(gè) view 之間的約束關(guān)系,添加到層次較高的父 view 上 自身的寬高等約束,添加到自身視圖上
特殊控件的約束
UILabel默認(rèn)內(nèi)容的顯示方式是垂直居中的。如果用autolayout給UILabel設(shè)置約束,只需要設(shè)置x、y、width,無需設(shè)置height,UILabel會(huì)自動(dòng)包裹內(nèi)容,并且隨內(nèi)容的多小而變化。如果我們通過約束給定了UILabel的width = 100,但是內(nèi)容仍然少的可憐,不能包裹,可以把寬度設(shè)置為<=100,此時(shí),label的寬高都能包裹住內(nèi)容。高度的設(shè)置同理可證。
當(dāng)然,我們也可以只給UILabel設(shè)置x、y。但必須要保證UILabel的text屬性有內(nèi)容,否則UILabel顯示不出來(這是初學(xué)者經(jīng)常犯的錯(cuò)誤)。原因在于,UILabel是根據(jù)內(nèi)容自動(dòng)調(diào)整寬度和高度,如果沒有內(nèi)容,那么寬度和高度就是0,導(dǎo)致UILabel無法顯示。
AutoLayout用法
XIB中設(shè)置AutoLayout
-
多個(gè)控件對(duì)齊處理
多個(gè)控件對(duì)齊處理 -
單個(gè)控件的處理
單個(gè)控件的處理Safe Area : iOS11中增加的,safe area 可以看作是系統(tǒng)在所有的 view 上加了一個(gè)虛擬的 view, 這個(gè)虛擬的 view 的大小等都是跟 view 的位置等有關(guān)的(當(dāng)然是在 iPhoneX上才有值) 以后在寫代碼的時(shí)候,自定義的控件都盡量針對(duì) safe area 這個(gè)虛擬的 view 進(jìn)行布局
Constrain to margins : 默認(rèn)會(huì)距邊框16px, iPhone6Pluse 準(zhǔn)備的,一般都會(huì)去掉
User Standard Value :使用標(biāo)準(zhǔn)的的值,而且這個(gè)值只有在是設(shè)置上下方向的時(shí)候才有用。默認(rèn)的值其實(shí)就是距離 Bottom Layout Guide,也就是上下基線。下基線就是距離視圖最底部。上基線就是距離StatusView下方的位置
User Current Canvas Value :使用當(dāng)前位置設(shè)置。默認(rèn)為當(dāng)前設(shè)置方向最近的一個(gè)VIew,且沒有覆蓋遮擋的視圖
注意:上下左右的間距和控件的寬度、高度配合使用,盡量不要沖突; 例如:375的屏幕寬度,你不能距離左邊200,距離右邊200,還要控件寬度100,肯定不行
建議:給了距離左邊的間距,同時(shí)給出空間寬度即可,適用于lable,textfile等控件,不考慮它到底距離右邊多少;如果給了距離左右的間距,就不要給寬度了,適用于button之類的控件。
-
更新、添加、清除約束
更新、添加、清除約束Selected Views : 處理當(dāng)前你選中View的約束問題,Clear Constraints 清除約束,會(huì)刪除選中的視圖的所有的約束
All Views in View Controller :處理當(dāng)前ViewController里所有的View的約束問題,Clear Constraints 會(huì)刪除當(dāng)前VC所有的約束
-
自適應(yīng)布局(Trait Variations)
Trait Variations替換了的Size Class??梢钥吹较旅鏅C(jī)型與自適應(yīng)的尺寸匹配起來,變得更加直觀
Trait VariationsDevice:在Device中,看到某個(gè)具體的機(jī)型,選擇設(shè)備,很容易被誤導(dǎo)以為特征變量會(huì)針對(duì)具體機(jī)型生效,其實(shí)并不是針對(duì)具體哪一個(gè)設(shè)備,而是相同sizeclass的一類設(shè)備,所以添加特征變量是影響一類設(shè)備
Interface Style:亮色或暗色的界面風(fēng)格
orientation:設(shè)備方向
Vary for Traits :點(diǎn)擊后會(huì)彈出選擇Width、Height復(fù)選框,選擇寬度、高度或兩者,背景會(huì)變成藍(lán)色,左邊顯示的設(shè)備也會(huì)變化,選擇設(shè)備后,點(diǎn)擊Done Varying按鈕
通過選中width復(fù)選框,將顯示varying 64 compact width devices通過選中height復(fù)選框,將顯示varying 98 compact height devices通過選中兩個(gè)復(fù)選框,將顯示varying 56 compact width regular height devices示例:
設(shè)備選擇iPhone8,亮色風(fēng)格,豎屏(布局:wC hR)復(fù)選框選擇height,會(huì)發(fā)現(xiàn)豎屏是可以的,橫屏中view不見了,因?yàn)閕Phone8的橫屏布局是(wC hC),所以添加約束不會(huì)生效,要想適配的話,需要在布局是(wC hC)條件下,重新添加約束
一般組合有4種結(jié)果(wC hC)、(wR hR)、(wC hR)、(wR hC) (w是width h是height,C是Compact R是Regular)
-(wC hR):它適用于一切尺寸的豎屏iPhone
-(wR hR):適用所有橫屏、豎屏iPad
-(wC hC):適用于iPhone的橫屏上(除了iPhone11、iPhone Plus等)
-(wR hC):適用于iPhone 11 、iPhone Plus的橫屏等
示例:
如果使用iPhone8 (wC hR)UI布局,且分類按鈕選了Width,那么如果對(duì)iPhone8的UI進(jìn)行修改,會(huì)使同為wC的設(shè)備比如(wC hC)、(wC hR)的UI產(chǎn)生改變
如果使用iPhone8 (wC hR)UI布局,且分類按鈕選了Height,那么如果對(duì)iPhone8的UI進(jìn)行修改,會(huì)使同為hR的設(shè)備比如(wR hR)、(wC hR)的UI產(chǎn)生改變
如果使用iPhone8 (wC hR)UI布局,且分類按鈕選了Width和Height,那么如果對(duì)iPhone8的UI進(jìn)行修改,會(huì)使同為(wC hR)的設(shè)備的UI產(chǎn)生改變
根據(jù)不同布局,不同分類選項(xiàng),對(duì)相應(yīng)的布局產(chǎn)生影響,總結(jié)如下:
| UI布局 | Width | Height | Width & Height |
|---|---|---|---|
| CR | CR、CC | CR、RR | CR |
| RC | RC、RR | RC、CC | RC |
| CC | CC、CR | CC、RC | CC |
| RR | RR、RC | RR、CR | RR |
在不同布局下,同一控件通過設(shè)置不同常數(shù)值實(shí)現(xiàn)相同效果,可以在配置在添加布局,而不是添加兩個(gè)約束

在不同設(shè)備上修改控件屬性,比如在iPhone豎屏上字體比較小,在iPhone橫屏上字體比較大,這時(shí)候使用Vary for Traits就沒有效果了,我們只需要為控件屬性增加布局,如果不需要點(diǎn)叉刪除

如果想指定尺寸選擇一個(gè)新控件,可以在控件屬性最下端,操作是類似,左邊的加號(hào)指定尺寸,Installed表示通用

-
修改約束
方式一:需要選中將要編輯的約束(上圖小標(biāo)1),選中后約束在視圖中顯示為高亮(上圖小標(biāo)2),右邊會(huì)顯示修改約束的設(shè)置(上圖小標(biāo)3)First Item:第一個(gè)要設(shè)置的控件約束
Second Item:第二個(gè)要參照的控件約束Relation:第一個(gè)控件與第二個(gè)控件約束值之間的關(guān)系
-Less Than or Equal:小于等于
-Equal:等于
-Greater Than or Equal:大于等于Constraint:約束的偏移量
Priority:約束的優(yōu)先級(jí)
-Required(1000):默認(rèn)優(yōu)先級(jí)(高優(yōu)先級(jí))
-Required(1000):中優(yōu)先級(jí)
-Required(1000):低優(yōu)先級(jí)Multiplier:約束值放大倍數(shù)
-Reverse Multiplier:反轉(zhuǎn)倍數(shù)(即 0.5 變?yōu)?2,4:3 變?yōu)?3:4)
-Convert to Decimal:轉(zhuǎn)換為十進(jìn)制
-Presets:預(yù)設(shè)值(也可以不使用預(yù)設(shè)值,自己設(shè)置需要的倍數(shù),如 0.5)
-1:1 倍
-4:3:4:3 倍
-16:9:16:9 倍Placeholder(Remove at build time):編譯時(shí)移除該約束
核心公式:第一個(gè)Item的屬性 =(<=/>=)第二個(gè)Item的屬性*Multiplier+Constant
方式二:
選中控件,選擇要修改的約束點(diǎn)擊Edit
-
預(yù)覽(通過PreView可看到各設(shè)備預(yù)覽)
如果xib完成一個(gè)效果,點(diǎn)擊PreView可以查看給個(gè)型號(hào)設(shè)備的效果.gif
代碼中設(shè)置AutoLayout
- 利用 NSLayoutConstraint 類創(chuàng)建具體的約束對(duì)象
-
添加、刪除約束對(duì)象到相應(yīng)的view上
- (void)addConstraint:(NSLayoutConstraint *)constraint - (void)addConstraints:(NSArray<__kindof NSLayoutConstraint *> *)constraints - (void)removeConstraint:(NSLayoutConstraint *)constraint - (void)removeConstraints:(NSArray<__kindof NSLayoutConstraint *> *)constraints
注意:
1.先禁止 autoresizing 功能,設(shè)置要添加約束的控件的下面屬性為 NO
testView.translatesAutoresizingMaskIntoConstraints = NO;
2.添加約束之前,一定要保證相關(guān)控件都已經(jīng)在各自的父控件上
[self.view addSubview:testView];
3.不用再給 view 設(shè)置 frame
-
示例:
redView(10,10,300,100)代碼實(shí)現(xiàn):
[self.view setBackgroundColor:[UIColor whiteColor]]; UIView *redView = [[UIView alloc]init]; redView.backgroundColor = [UIColor redColor]; [self.view addSubview:redView]; //先禁止 autoresizing 功能,設(shè)置要添加約束的控件的下面屬性為 NO redView.translatesAutoresizingMaskIntoConstraints = NO; /* + (instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(nullable id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c view1:要約束的控件 attr1:要約束的類型(上、下、左、右等等) relation:與參照控件關(guān)系(小于等于、等于、大于等于) view2:參照控件 attr2:要約束的類型(上、下、左、右等等) multiplier:約束值放大倍數(shù) c:偏移量 */ //redView(10,10,300,100) NSLayoutConstraint *xConstraint = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:10]; [self.view addConstraint:xConstraint]; NSLayoutConstraint *yConstraint = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0 constant:10]; [self.view addConstraint:yConstraint]; NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant:300]; [redView addConstraint:widthConstraint]; NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:redView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant:100]; [redView addConstraint:heightConstraint];













