什么是AutoLayout
AutoLayout是iOS6時引入的一個全新的布局引擎,用來解決原始手動布局低效率難維護的問題,以及更好地適配未來多尺寸機型。
目前還有很多開發者不愿使用AutoLayout來布局,我想主要是對于其性能的擔憂。在iOS12上,Apple大幅提高了布局算法Cassowary在AutoLayout上的性能,所以習慣手動布局的開發者不妨乘此機會嘗試下自動布局。
原生自動布局NSLayoutConstraint
Apple提供了NSLayoutConstraint類讓開發者實現自動布局。下面就是用NSLayoutConstraint生成控件約束的方法。一般開發中很少直接用原生方法,經常依賴一些三方庫,如Masonry等,實現自動布局。
// 這就是利用NSLayoutConstraint實現布局要調用的方法
+(instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(nullable id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c;
// 參數解釋
1.view1: 被約束的控件;
2.attr1: 被約束控件的約束類型(常量),也就是被約束控件要被做什么樣的約束(比如NSLayoutAttributeLeft);
3.relation: 被約束控件與約束參照控件的約束類型之間的關系(常量),包括等于、大于等于、小于等于等;
4.view2: 提供約束參照的控件;
5.attr2: 約束參照控件提供的約束類型(常量),也就是被約束控件以參照控件的什么約束類型為參照建立自己的約束(比如NSLayoutAttributeLeft);
6.multiplier: 乘數,就是多少倍;
7.c: 常量,做好了上述的約束之后會加上這個常量。
生成NSLayoutConstraint對象后,往哪個控件添加呢?一般都采用如下原則:
-
對于兩個同層級 view 之間的約束關系,添加到它們的父 view 上;
image1.png -
對于兩個不同層級 view 之間的約束關系,添加到他們最近的共同父 view 上;
image2.png -
對于有層次關系的兩個 view 之間的約束關系,添加到層次較高的父 view 上;
image3.png - 對于比方長寬之類的約束,只作用在該 view 自己身上的話,添加到該 view上。
NSLayoutConstraint布局示例
由于NSLayoutConstraint布局語法太過冗長,所以就布局一個簡單的ViewView(top:50,left:50,width:150,height:150)來做示例。
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor whiteColor];
UIView *layoutView = [[UIView alloc]init];
layoutView.backgroundColor = [UIColor purpleColor];
// 禁止 autoresizing 功能,防止 AutoresizingMask 轉換成 Constraints,避免造成約束沖突
layoutView.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:layoutView];
NSLayoutConstraint *widthConstraint = [NSLayoutConstraint constraintWithItem:layoutView attribute:(NSLayoutAttributeWidth) relatedBy:(NSLayoutRelationEqual) toItem:nil attribute:(NSLayoutAttributeNotAnAttribute) multiplier:0 constant:150];
[layoutView addConstraint:widthConstraint];
NSLayoutConstraint *heightConstraint = [NSLayoutConstraint constraintWithItem:layoutView attribute:(NSLayoutAttributeHeight) relatedBy:(NSLayoutRelationEqual) toItem:nil attribute:(NSLayoutAttributeNotAnAttribute) multiplier:0 constant:150];
[layoutView addConstraint:heightConstraint];
NSLayoutConstraint *leftConstraint = [NSLayoutConstraint constraintWithItem:layoutView attribute:(NSLayoutAttributeLeft) relatedBy:(NSLayoutRelationEqual) toItem:self.view attribute:(NSLayoutAttributeLeft) multiplier:1.0 constant:50];
[self.view addConstraint:leftConstraint];
NSLayoutConstraint *topConstraint = [NSLayoutConstraint constraintWithItem:layoutView attribute:(NSLayoutAttributeTop) relatedBy:(NSLayoutRelationEqual) toItem:self.view attribute:(NSLayoutAttributeTop) multiplier:1.0 constant:50];
[self.view addConstraint:topConstraint];
}
布局效果見下圖
image4.png
NSLayoutConstraint布局注意點
布局時,要注意以下三點:
- 要先禁止 autoresizing 功能,防止 AutoresizingMask 轉換成 Constraints,避免造成約束沖突,需要設置 :layoutView.translatesAutoresizingMaskIntoConstraints = NO;
- 添加相對約束之前,一定要保證相關控件都已經在各自的父控件上。用上面的例子就是 [self.view addSubview:layoutView] 一定要放在添加 left 約束之前,否則程序會 crash;
- 不用再給layoutView設置 frame。