AutoLayout是苹果在iOS6.0以后推出的多屏幕适配的布局工具,然而实际上它不仅仅是一种布局工具,它还是一种全新的布局思想。
AutoLayout是通过约束来实现布局的,一个UIView对象一旦使用的AutoLayout,那么它的frame属性将一直为0。
在使用AutoLayout进行布局之前我们先要做一些准备工作:
translatesAutoresizingMaskIntoConstraints = NO
。简单来说,Autoresizing和AutoLayout是两种不同的布局理念,但是默认情况是是可以转化的,这里我们需要指定使用AutoLayout进行布局,禁止Autoresizing。- (void)updateViewConstraints
方法中;如果是UIView则可以将约束写在- (void)updateConstraints
方法中。AutoLayout我们可以看成主要是对视图进行三种类型的约束:
而无论是哪种约束,其在底层的实现主要是依赖于NSLayoutConstraint
这个类。
NSLayoutConstraint
这个类主要有两个类方法,用于给视图添加约束的。其中可以以VFS
方式进行约束的描述,或者以常规方式描述视图间约束条件。
我们可以先来看一下这两个添加约束条件的方法。
+ (NSArray<__kindof NSLayoutConstraint *> *)constraintsWithVisualFormat:(NSString *)format
options:(NSLayoutFormatOptions)opts
metrics:(NSDictionary<NSString *,id> *)metrics
views:(NSDictionary<NSString *,id> *)views
第一个添加约束的方法是使用
VFS
,fotmat
则为传入的表达式,options
选项可以对描述的约束进行进一步的设置。
我们更常用的是使用以下这个方法对约束进行描述,该方法可以对单个视图进行设置,也可以设置两个视图间的约束关系。
+ (instancetype)constraintWithItem:(id)view1
attribute:(NSLayoutAttribute)attr1
relatedBy:(NSLayoutRelation)relation
toItem:(id)view2
attribute:(NSLayoutAttribute)attr2
multiplier:(CGFloat)multiplier
constant:(CGFloat)c
参数说明:
- view1: 被约束对象
- attribute: 被约束对象的属性(比如说是上下左右边距之类的)
- relatedBy: 约束关系。主要是等于,大于等于,小于等于三种关系。
- toItem: 约束源
- attribute: 约束源的属性,同被约束源。这两个结合说明了两者之间某两个属性的关系。
- multiplier: 约束系数。
- constant: 约束常数。
在官方说明中是这样描述约束的计算的。
view1.attr1 = view2.attr2 * multiplier + constant
接下来我们将对三种约束种类做一个简单说明。
视图大小的约束的话主要是值针对被约束对象的,可以看做是没有约束源的约束。我们可以通过把约束源设置为nil
来实现约束。
[self.view1 addConstraint:
[NSLayoutConstraint constraintWithItem:self.view1
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:0.0f
constant:200]];
[self.view1 addConstraint:
[NSLayoutConstraint constraintWithItem:self.view1
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:0.0f
constant:200]];
这里我们把约束源设置为了nil
,如果此时约束源的属性也不存在时。可以用NSLayoutAttributeNotAnAttribute
来描述,表示没有属性。上面那个设置的意思则是说明指定view1的宽度和高度都等于200。
PS:最后别忘了把获取的NSLayoutConstraint约束实例添加到对应的视图中!!!!!!!,其中视图大小的约束应该只添加到视图自身
视图间相对位置包括了上下左右间距之类的位置关系。需要注意的是视图间相对位置的约束可能会有以下情况。
[self.view2 addConstraint:
[NSLayoutConstraint constraintWithItem:self.view2
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:0.0f
constant:100]];
[self.view2 addConstraint:
[NSLayoutConstraint constraintWithItem:self.view2
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:0.0f
constant:100]];
[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:self.view2
attribute:NSLayoutAttributeTopMargin
relatedBy:NSLayoutRelationEqual
toItem:self.view1
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:20]];
正如上面的代码所示,前两个是约束视图大小的约束则添加到其自身,而第三个约束是让view2位于view1下方距离20的位置,并且它们有共同的父视图,所以这个约束是添加到它们共同的父视图中的。
视图对齐约束的话包括中心X/Y的对齐,上下左右边界的对齐等等。其视图添加原则和上面是类似的。
[self.view3 addConstraint:
[NSLayoutConstraint constraintWithItem:self.view3
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:0.0f
constant:100]];
[self.view3 addConstraint:
[NSLayoutConstraint constraintWithItem:self.view3
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:0.0f
constant:100]];
[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:self.view3
attribute:NSLayoutAttributeCenterX
relatedBy:NSLayoutRelationEqual
toItem:self.view1
attribute:NSLayoutAttributeCenterX
multiplier:1.0f
constant:0]];
[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:self.view3
attribute:NSLayoutAttributeCenterY
relatedBy:NSLayoutRelationEqual
toItem:self.view1
attribute:NSLayoutAttributeCenterY
multiplier:1.0f
constant:0]];
这段代码实现了约束view3的宽高为100,并且其中心位置在X/Y轴方向上居中于view1。
我们可以看到上面代码的实现效果图。红色为view1,蓝色为view2,绿色为view3。
我们通过上面很简单的例子可以看到,虽然可以实现铜鼓约束来进行布局,但是代码还是比较冗长的,而且约束间关系也需要非常细心的思考才能确保约束的正确。
实际上现在已经有很多开源的第三方库,它们都封装了AutoLayout,以达到简化代码量,提高代码复用性的目的。比如常用的有AutoLayout
、Masonry
等,接下来我们也会对这些第三方库进行一个学习。
这里给出的是Github上的源码地址。
iOS-Demon——AutoLayoutDemon