為什么需要代碼實現 AutoLayout
- 實際開發中我們經常需要通過代碼來添加控件,此時創建的控件是無法通過 storyboard 設置約束的
- 通過 storyboard 添加的約束本質上是會轉成代碼的。
添加約束的規則
- 對于兩個同層級的 View 的約束。添加到他們的父控件上
- 對于兩個不同層級的view之間的約束,添加到他們最近層次的父控件上
- 對于有層次關系的 view 添加到較高級的父控件上
- 對于跟其他沒有關系的view 約束添加到他自己本身
總結:添加到能夠管理到需要約束控件的最近父級控件上。就像在族譜上找兩個人的共同祖先一樣。
下面我們通過簡單的圖示幫助理解上述的幾個規則
兩個同層級的 View 的約束
兩個不同層級的 View 的約束
兩個有層次關系的 view 的約束
注:不同顏色表示不同組,箭頭所指的元素為添加約束的元素,如三個藍色元素,兩個沒有箭頭指向的表示需要添加約束的元素,箭頭指向的元素為約束添加到該元素身上。其他不同顏色組也是如此。
代碼實現
假設有這樣一個簡單需求:有一個 UIView 寬高均為 100,在不同屏幕尺寸下,均位于屏幕右下角,距右邊框和下邊框均為 10。示意圖如下:
需求示意圖
在開始代碼之前我們先來了解一下關鍵的方法
1.創建約束對象
+(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:與參照之間的關系(如:等于,大于)
view2:參照的控件
attr2:約束的類型(如: view2 的寬度)
multiplier:乘數
c:減去的常量
舉個例子
要約束的對象(通過 view1 指定)的高度(通過 attr1 指定)等于(通過 relation 指定) 所參照的控件(通過 view2 指定)的寬度(通過 attr2 指定)的 2 倍(通過 multiplier 指定)減去 20(通過 c 指定)
2.添加約束
- (void)addConstraint:(NSLayoutConstraint *)constraint
核心代碼
- (void)viewDidLoad {
[super viewDidLoad];
//添加一個視圖
UIView * greenView = [[UIView alloc] init];
greenView.backgroundColor = [UIColor greenColor];//設置背景顏色
[self.view addSubview:greenView];//先添加控件再添加約束
//注意點,系統默認會將 autoresizingMask 轉成約束,這種情況下會與我們設置的Autolayout 約束沖突,下面指令告訴系統不要自動轉換。
greenView.translatesAutoresizingMaskIntoConstraints = NO;
//創建約束
//寬度約束
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:greenView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant:100];
//添加寬度約束
[greenView addConstraint:widthConstraint];
//高度約束
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:greenView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant:100];
//添加寬度約束
[greenView addConstraint:heightConstraint];
//距離屏幕右邊約束
NSLayoutConstraint *rightMargin = [NSLayoutConstraint constraintWithItem:greenView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0 constant:-10];
//添加距離屏幕右邊約束
[self.view addConstraint:rightMargin];
//距離屏幕底部約束
NSLayoutConstraint *bottomMargin = [NSLayoutConstraint constraintWithItem:greenView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-10];
//添加屏幕底部約束
[self.view addConstraint:bottomMargin];
}
程序運行圖
運行效果
運行效果
注意點總結:
- 每一個約束都是一個約束對象
- 添加約束的規則,添加到約束涉及到的控件的最近一父級控件身上
- translatesAutoresizingMaskIntoConstraints = NO 避免沖突
- 先添加控件再添加約束
- 不參照第二個控件的時候 attr2 屬性傳 NSLayoutAttributeNotAnAttribute