AutoLayout之NSLayoutConstraint
2019-05-12 本文已影响0人
黄定师
什么是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。