AutoLayout概念是蘋果自iOS6開始引入的概念。
目前為止,實現自動布局技術選型方面也可以使用xib和storyboard。在開發過程中通常登錄、注冊等變動可能性較小的視圖,我會采用xib開發,其他頁面通常會采用Masonry布局。xib和手碼各有優勢,視情況而定。
關於NSLayoutAttributeLeading和NSLayoutAttributeTrailing,前邊和后邊並不是總是為左邊和右邊的,有些國家的前邊是右邊后邊是左邊所以這樣設定是為了國際化考慮。還有視圖基准線NSLayoutAttributeBaseline通常是指視圖的底部放文字的地方。
使用NSLayoutConstraint之前,我們需要確定一點:為了防止constraint和view本身的autoresizing屬性沖突,我們需要設置view的屬性:
view.translatesAutoresizingMaskIntoConstraints = NO;
一、UIKit框架提供的自動布局的方法一,詳細請看參數介紹:
/**
設置約束
@param view1 指定需要添加約束的視圖一
@param attr1 指定視圖一需要約束的屬性
@param relation 指定視圖一和視圖二添加約束的關系
@param view2 指定視圖一依賴關系的視圖二;可為nil
@param attr2 指定視圖一所依賴的視圖二的屬性,若view2=nil,該屬性設置 NSLayoutAttributeNotAnAttribute
@param multiplier 系數 情況一和二為親測
情況一:設置A視圖的高度 = A視圖高度 * multiplier + constant;此時才會起作用;
情況二:設置A視圖和其他視圖的關系或 toItem=nil,multiplier設置不等於0即可,若等於0會crash;
@param c 常量
@return 返回生成的約束對象
*/
+ (instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(nullable id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c;
以上函數設置的約束等價於 view1.att1 =(以等號舉栗子,relation可> < ≥≤)view2.attr2 * multiplier + c;
簡單小需求:隨意在控制器中添加一個紅色view:
// 設置 redView 的寬 = 100.f * 1.f
NSLayoutConstraint *redViewWidthConstraint =
[NSLayoutConstraint constraintWithItem:self.redView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.f
constant:100.f];
// 設置 redView 的高 = 100.f * 1.f
NSLayoutConstraint *redViewHeightConstraint =
[NSLayoutConstraint constraintWithItem:self.redView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.f
constant:100.f];
// 設置 redView 的前面(左邊) = self.view.leading + 20.f
NSLayoutConstraint *redViewleadingConstraint =
[NSLayoutConstraint constraintWithItem:self.redView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeading
multiplier:1.f
constant:20.f];
// 設置 redView 的頂部
NSLayoutConstraint *redViewTopConstraint =
[NSLayoutConstraint constraintWithItem:self.redView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTop
multiplier:1.f
constant:30.f];
[self.view addConstraint:redViewWidthConstraint];
[self.view addConstraint:redViewHeightConstraint];
[self.view addConstraint:redViewleadingConstraint];
[self.view addConstraint:redViewTopConstraint];
小注:
1、關於參數 multiplier
✅舉個栗子🌰:
[NSLayoutConstraint constraintWithItem:aView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:aView
attribute:NSLayoutAttributeWidth
multiplier:2.f
constant:100.f];
等價於 aView的高 = aView的寬 * 2.f + 100.f;
2、❌本來想逃懶,下面的寫法,經過我實驗是錯誤的
[NSLayoutConstraint constraintWithItem:self.redView
attribute:NSLayoutAttributeWidth | NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.f
constant:100.f];
二、UIKit框架提供的自動布局的方法二,VFL語言來實現自動布局:
/**
Description
@param format VFL語句,舉個栗子:@"H:|-[_redView]-padding-|"
@param opts 枚舉參數,默認寫0
@param metrics 字典,key值為VFL語句中的變量 padding,value為指定的值: @{@"padding" : @50}
@param views VFL語句中使用到的視圖
*/
+ (NSArray<__kindof NSLayoutConstraint *> *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(nullable NSDictionary<NSString *,id> *)metrics views:(NSDictionary<NSString *, id> *)views;
舉個栗子:
NSArray *constraints1 =
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_redView]-padding-|"
options:0
metrics:@{@"padding" : @50}
views:NSDictionaryOfVariableBindings(_redView)];
NSArray *constraint2 =
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-height-[_redView(height)]"
options:0
metrics:@{@"height" : @20}
views:NSDictionaryOfVariableBindings(_redView)];
[self.view addConstraints:constraints1];
[self.view addConstraints:constraint2];
關於UILabel自動布局,需要注意的是若label多行顯示,可通過設置numberOfLines:
UILabel *label = [[UILabel alloc] init];
label.translatesAutoresizingMaskIntoConstraints = NO;
label.text = @"Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~";
label.textColor = [UIColor blackColor];
label.backgroundColor = [UIColor redColor];
label.numberOfLines = 0;
[self.view addSubview:label];
NSArray *labelConstraintsH =
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[label]-20-|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(label)];
NSArray *labelConstraintsV =
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-30-[label]"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(label)];
[self.view addConstraints:labelConstraintsH];
[self.view addConstraints:labelConstraintsV];
注意:
1、VFL語句中具體浮點型不可以使用 56.f 諸如此類,會crash;
2、VFL語句中的視圖,不要使用self.xxx屬性,而要使用變量_xxx,會crash
3、addConstraint之前,必須保證subView已擁有superView
4、視圖的 translatesAutoresizingMaskIntoConstraints 必須設置為NO,
5、通常使用的是Masonry\SnapKit自動布局的三方庫,簡單高效。校之frame布局,自動布局更適合業務拓展。

