iOS回顧筆記(06) -- AutoLayout從入門到精通
隨着iOS設備屏幕尺寸的增多,當下無論是純代碼開發還是Xib/StoryBoard開發,自動布局已經是必備的開發技能了。
我使用自動布局也有一段時間了,遇到了不少問題,在解決的過程中也收獲了很多知識。尤其是在使用熟練之后開發速度上的提升非常明顯。這里把AutoLayout的基本使用和個人使用心得匯總一下,希望能幫助到大家!
適配的概念
適配主要分兩種
-
系統適配
系統適配主要指適配不同版本系統,如 iOS 6(擬物化) 到 iOS 7(扁平化)兩個系統系統的適配,我們需要寫不同的代碼來保證項目在不同系統上的美觀與可用。
-
屏幕適配
屏幕適配主要是針對不同尺寸的屏幕進行適配,同一個頁面再不同尺寸屏幕上的布局,如Safari在手機橫豎屏下的布局等等。
常見設備的分辨率:

屏幕適配發展史
- iPhone 4s 以前的時代
iPhone 4s 和之前設備的屏幕都是3.5英寸,可以說沒有屏幕適配,所有的坐標點就是 320*480.
適配完全使用frame、bounds、center進行計算,代碼基本寫死。
// 直接寫死
UIImageView *iv = [UIImageView new];
iv.frame = CGRectMake(50, 300, 200, 80);
[self.view addSubview:iv];
-
iPad、iPhone橫屏時代
-
出現 AutoResizing 技術
-
優點:
- 解決了父子控件相對位置的問題
- 子控件可根據父控件的行為發生相對應的變化
- 讓橫豎屏的適配變得簡單
- 無法處理兄弟控件相對位置的問題
-
使用前提:
- 關閉AutoLayout
-
局限性:
- 只能解決父子控件的相對關系,
- 無法解決兄弟控件之間的相對關系
-
-
AutoResizing在Xib中的使用介紹
在Xib中主要有6根線來設置AutoResizing
-

外部四根線
外部四根線分別表示上、下、左、右四個方向,子控件相對於父控件的距離。
實線:表示固定位置
虛線:表示非固定位置
**內部兩根線**
內部兩根線分別表示水平和豎直方向,子控件是否根據父控件等比例縮放。
實線:該方向上跟隨父控件等比縮放
虛線:該方向上不跟隨父控件等比縮放
- **AutoResizing在代碼中的使用介紹**
通常代碼中子控件在添加到父控件之前設置AutoResizing對應的屬性值,其代碼屬性值和Xib中相反,代碼中設置可變部分,Xib中是選中部分為固定不變的。
// 上下左右四個方向參數(與Xib中設置相反)
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexibleLeftMargin = 1 << 0,
UIViewAutoresizingFlexibleRightMargin = 1 << 2,
UIViewAutoresizingFlexibleTopMargin = 1 << 3,
UIViewAutoresizingFlexibleBottomMargin = 1 << 5
// 寬高是否根據父控件等比縮放
UIViewAutoresizingFlexibleHeight = 1 << 4,
UIViewAutoresizingFlexibleWidth = 1 << 1,
比如要設置一個UIView與其父控件關系為右下角對齊
示例代碼如下:
XYBannerView *banner = [XYBannerView bannerView];
banner.frame = CGRectMake(80, 20, 200, 90);
banner.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin;
[self.view addSubview:banner];
-
iOS 6之后
- 出現了AutoLayout技術
AutoLayout彌補了AutoResizing的局限性,不僅可以解決父子控件之間的相對關系,還可以描述兄弟控件之間的相對關系,還可以描述自身關系等,功能非常強大。
AutoLayout的兩個核心概念
- 參照
- 約束
AutoLayout介紹和使用
Xib中常用的面板
Xib 主要有以下三個面板
- Align : 對齊方式

- Add New Constraint: 添加新的約束

- Resolve Auto Layout Issues : 修復自動布局問題

AutoLayout的使用原則
AutoLayout是為了確定View的frame(確定View的Point和Size)。
- 至少添加四個約束,寬高和位置來確定frame
- 避免約束沖突:
1.如同一個View的寬設置兩次,一個100,一個200,導致無法確定,形成沖突,沖突屬於錯誤,須解決:
2.如約束不夠,無法確定View的frame時候也會報錯:

-
AutoLayout的警告:警告一般是Xib中添加好了約束,但是對應View沒有移動到對應位置導致。這種情況程序運行起來之后會是正確約束的樣子,而不是Xib中的樣子。
- 警告解決辦法:
1.選中View,update frame 或使用快捷鍵‘command’ + ‘option’ + ‘=’
2.如圖:
- 警告解決辦法:
-
約束的修改:
約束的修改有很多種方式,下面列舉一種我常用的方式!

注意:上面說的Add New Constaints面板只能添加新的約束,修改不能在那里。
AutoLayout案例練習
AutoLayout這種靈活的實用技術最直接的學習辦法就是實戰練習,下面幾個小案例來展示一下。
練習1
1.在控制器底部添加兩個View,一個紅色,一個藍色
2.兩個View的高度、寬度永遠相等
3.距離父控件左邊、右邊、兩者中間和距底邊的距離相等
示意如圖:

根據:添加四個約束確定frame,避免沖突和警告的原則。我們按照要求添加約束
1.兩者等高等寬:使用Add New Constraints面板

或者可以直接拖線:選中紅色 按住‘control’鍵拖線到藍色

2.設置紅色View約束
選中紅色View打開Add New Contraint面板設置對應約束

3.設置藍色View約束
選中紅色View打開Add New Contraint面板設置對應約束,其中藍色View的約束同上圖,只需要設置藍色的右邊距同紅色相等 為 20 即可(其他約束在設置紅色的時候已經有了)
4.設置紅藍色View等高/底
設置等高/底 和上面設置兩者等高等寬步驟一致,選擇 Top/Bottom即可。
效果:

練習2
同樣兩個View 一藍一紅
1.兩個View的高度相等
2.紅色View和藍色View的右邊對齊
3.藍色View距離父控件的左右相等,且距離紅色View的間距相等
4.紅色View的左邊和藍色View中點對齊

1.設置藍色View約束
藍色View約束:距離父控件邊距和紅色View的邊距

2.設置紅色View和藍色View等高 和邊距
1.設置兩者等高,直接拖線即可
2.設置紅色view的邊距直:距右 20 和 距底邊 20。(參考上圖)
3.設置紅色View與藍色View的中心對齊
紅色View和藍色View的中心對齊可轉化為 紅色View長度為藍色一半。可先設置等寬再修改等寬約束。

效果圖:

練習3
四個相同的View均分占據屏幕的四個角,如圖

1.四個view是等寬等高
直接分別設置四個的等寬等高,拖線就很方便
2.四個view互相之間的間距為零
使用Add New Contraint面板分別添加每個View的四邊距 為0即可
最終效果如圖:

AutoLayout 中的UILabel
UILabel相對比較特殊一點,需要單獨說一下。
在不使用 AutoLayout的時候 UILabel 內部的文字默認是居中顯示的,如果設置的Size較大,而內部文字較少就會造成上下留白,從而造成資源的浪費。
在實際的使過程中,需求往往是UILabel正好包裹住內部的文字。
有了AutoLayout之后的UILabel在添加約束的時候可以不用添加高度,系統會自動計算內部文字高度來自適應UILabel的高度!

實際應用中經常需要設置UILabel的根據文字多少來自動適應高度,並且UILabel.width <= 某個值.
這種情況需要給UILabel添加寬度約束,比例關系設置為Less Than Or Equal

練習4
1.設置兩個View,兩者間距為0,一紅一綠,
2.紅色View內部有一個UILabel,
3.根據Label內部的文字自適應高度,
4.點擊屏幕修改Labe內部文字,讓其父控件的frame也自動適應

1.設置兩個View一紅一綠,分別設置邊距等約束
2.紅色View中添加UILabel,設置Label的文字和約束,設置Label高度自適應
最終效果圖:

這只是幾個簡單的小練習,若想使用熟練AutoLayout還需要認真練習
AutoLayout在代碼中的使用
以上講了AutoLayout的可視化使用,但是項目中有很多頁面是動態生成的,需要我們用代碼實現,所以下面講講AutoLayout的代碼實現
代碼實現的特點:繁瑣、技術含量低
Xib中的每一條拖線對應代碼中一個 NSLayoutConstraint 對象,從NSLayoutConstraint頭文件中可以查看其對象的創建方法:
NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:view1
attribute:attr1 relatedBy:NSLayoutRelation toItem:view2 attribute:attr2
multiplier:multiplier constant:c];
參數含義:
view1: 約束的第1個View
attr1: 第1個View的屬性
NSLayoutRelation: 兩個View的屬性之間的關系
view2: 約束的第2個View
attr2: 第2個View的屬性
multiplier: 倍數關系
c: 需要增加的常量
上面的方法可以整合成一個自動布局的核心計算公式
obj1.property = (obj2.property) * multiplier + c
代碼添加AutoLayout的步驟
- 利用NSLayoutConstraint類創建具體的約束對象
- 添加約束到對應的View上
- (void)addConstraint:(NSLayoutConstraint *)constraint;
- (void)addConstraints:(NSArray<__kindof NSLayoutConstraint *> *)constraints;
代碼添加AutoLayout的注意點
- 需要先禁止AutoResizing功能,設置如下
view.translatesAutoresizingMaskIntoConstraints = NO;
- 添加約束之前,確保所有View已經添加到父控件上
- 設置AutoLayout之后無需再設置frame
代碼添加約束的規則
- 對於兄弟控件之間的約束要添加到共同的父控件上
- 對於不同層級的'兄弟'控件的約束要添加到最近的‘父控件’上
- 兩個父子控件之間的約束要添加到父控件上
下面代碼實現一個如圖自動布局

UIView * view = [UIView new];
view.translatesAutoresizingMaskIntoConstraints = NO;
view.backgroundColor = [UIColor redColor];
// view.frame = CGRectMake(10, 10, 100, 100); ---> 不再設置frame
[self.view addSubview:view];
//設置底邊約束
NSLayoutConstraint * bottomConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-10];
//設置右邊約束
NSLayoutConstraint * rightConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0 constant:-10];
//設置width約束
NSLayoutConstraint * widthConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0 constant:100];
//設置height約束
NSLayoutConstraint * heightConstraint = [NSLayoutConstraint constraintWithItem:view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0 constant:100];
[self.view addConstraint:bottomConstraint]; ----> 與父控件相關的約束添加到父控件上
[self.view addConstraint:rightConstraint];
[view addConstraint:widthConstraint];
[view addConstraint:heightConstraint];
代碼實現AutoLayout相對比較繁瑣,但是如果懂得了原理還是能很好實現出來的。
AutoLayout三方框架
由於AutoLayout技術代碼實現起來特別繁瑣,並且技術含量不高、代碼冗余等問題。有一些大牛開源了一些自己寫的三方自動布局框架,使用起來非常簡單。
目前最流行的是:Masnory
至於使用方法請自行搜索、學習。
小結
- AutoLayout功能強大、是現在屏幕適配的首選
- AutoLayout在Xib上使用非常簡單靈活,代碼實現非常繁瑣
- 自動布局非常靈活,想要熟練需要多用多練
重要的事情多說一遍:自動布局非常靈活,想要熟練需要多用多練
