一、介绍
说起自动布局,什么masonry或者sd_autolayout等三方库,都是基于原生的NSLayoutContraint来写的,所以有必要知道NSLayoutContraint这个东西。
二、发展史
1、屏幕适配发展的路线:
1)纯代码计算frame(最早是通过计算frame实现布局)
2)autoresizing(仅适用于约束父子控件之间的关系)
3)AutoLayout(iOS6/2012年、iPhone5被引入,比autoresizing更加高级,旨在替代autoresizing,可以设置任何控件之间的关系)
4)sizeClass(iOS8出现,用于解决越来越多的屏幕尺寸的适配问题)。
2、为什么总是在变换屏幕布局的方式?
三、Autoresizing
Xcode5之后,新建的项目默认使用AutoLayout。Autoresizing默认不启用,我们可以去掉use Auto Layout,Use Size Classes前面的对勾来启用Autoresizing,如下图:
当UIView的autoresizesSubviews是YES时(默认是YES), 那么在其中的子view会根据它自身的autoresizingMask属性来自动适应其与superView之间的位置和大小。通俗易懂的话语来讲就是:当父视图被拉伸的时候,子视图能够适配父视图的新大小。其原理是,子视图有一个masks,用于指定与父视图上下左右边缘的距离,以及自身宽高的关系。比如,指定子视图的右边缘紧跟着父视图的右边缘,那么父视图变大之后,子视图还是贴在父视图的右边。这在大部分简单布局情况下非常有效。
四、Autolayout
1、AutolayoutContraint
AutoLayout是从IOS 6开始苹果引入来取代autoresizing的新的布局技术,该技术有三种设置方式,在说三种设置方式前,我们先简单的说一下autolayout能够设置哪些行为。3)视图的对齐方式(相对于父视图或者相对于兄弟视图)。
+(instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(nullable id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c
#pragma mark -methodOne
- (void)methodOne{
_redV = [[UIView alloc] initWithFrame:CGRectZero];
_redV.backgroundColor = [UIColor redColor];
[self.view addSubview:_redV];
//为了防止constraint和view的zutoresizing属性冲突,我们需要设置view的属性
self.redV.translatesAutoresizingMaskIntoConstraints = NO;
/*
@param item1 指定需要添加约束的视图一
@param attribute 指定视图一需要约束的属性
@param relatedBy 指定个视图一和视图二添加约束的关系
@param item2 指定视图一依赖关系的视图二,可为nil
@param attribute 指定视图一所依赖的视图二的属性,若view2 = nil,该属性设置NSLayoutAttributeNotAnAttribute
@param multiplier 系数 情况一:设置A视图的高度 = A视图高度 * multiplier + constant;此时才会起作用;
情况二:设置A视图和其他视图的关系或 toItem=nil,multiplier设置不等于0即可,若等于0会crash;
@param
*/
//设置redView的宽 = 100.f
NSLayoutConstraint * readViewW = [NSLayoutConstraint constraintWithItem:self.redV
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.f
constant:100.f];
//设置readView的高 = 100.f
NSLayoutConstraint * readViewH = [NSLayoutConstraint constraintWithItem:self.redV
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:100.f];
//设置readView的左 = 20.f
NSLayoutConstraint * readViewL = [NSLayoutConstraint constraintWithItem:self.redV
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeLeading
multiplier:1.f
constant:20.f];
//设置readView的上 = 50.f
NSLayoutConstraint * readViewT = [NSLayoutConstraint constraintWithItem:self.redV
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeTop
multiplier:1.f
constant:50.f];
//添加约束到视图
[self.view addConstraint:readViewW];
[self.view addConstraint:readViewH];
[self.view addConstraint:readViewL];
[self.view addConstraint:readViewT];
}
2、VFL 语言
1)什么是 VFL 语言:
VFL(Visual Format Language),“可视化格式语言”。
VFL是苹果公司为了简化autolayout的编码而推出的抽象语言
功能 | 表达式 |
---|---|
水平方向 | H: |
垂直方向 | V: |
Views | [view] |
关系 | >=,==,<= |
SuperView | | |
空间,间隙 - | - |
优先级 | @value |
3)具体的方法
+ (NSArray<__kindof NSLayoutConstraint *> *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(nullable NSDictionary<NSString *,id> *)metrics views:(NSDictionary<NSString *, id> *)views;
4)具体说一下参数
format 就是填写刚刚咱们学习的 VFL 语言,注意,这里是需要将 VFL语言写成字符串传递进去,所以这一步很容易出错,错了也不会有报错提示,需要咱们平日里多加练习与锻炼才能很好的避免一些错误
typedef NS_ENUM(NSInteger, NSLayoutRelation) {
NSLayoutRelationLessThanOrEqual = -1, //小于等于
NSLayoutRelationEqual = 0, //等于
NSLayoutRelationGreaterThanOrEqual = 1, //大于等于
};
typedef NS_ENUM(NSInteger, NSLayoutAttribute) {
NSLayoutAttributeLeft = 1, //左侧
NSLayoutAttributeRight, //右侧
NSLayoutAttributeTop, //上方
NSLayoutAttributeBottom, //下方
NSLayoutAttributeLeading, //首部
NSLayoutAttributeTrailing, //尾部
NSLayoutAttributeWidth, //宽度
NSLayoutAttributeHeight, //高度
NSLayoutAttributeCenterX, //X轴中心
NSLayoutAttributeCenterY, //Y轴中心
NSLayoutAttributeBaseline, //文本底标线
NSLayoutAttributeNotAnAttribute = 0 //没有属性
};
NSLayoutAttributeLeft/NSLayoutAttributeRight 和NSLayoutAttributeLeading/NSLayoutAttributeTrailing的区别是left/right永远是指左右,而leading/trailing在某些从右至左习惯的地区会变成,leading是右边,trailing是左边。
metrics 表示使用到的度量数组,你可以把一些VFL 语言用的值定义在一个字典里面例如创建一个字典
NSDictionary *metres = @{@"leftArglin":@20}
然后在 VFL 语言里面所用到的距离左边位置的距离,可以用leftArglin 来代替,这样的话,改想要修改距离左边的距离,就致用修改字典里面的数值,而不用每个使用到左边距离的地方都意义修改,方便大家,当然这个值可以传 nil
views:就是上面所加入到NSDictionary中的绑定的View,就是需要布局的 view 都需要写入一个字典里面来才可以.
- (void)methodTwo{
//VFL(可视化格式语言)
_blueV = [[UIView alloc]init];
_blueV.backgroundColor = [UIColor redColor];
[self.view addSubview:_blueV];
_yellowV = [[UIView alloc]init];
_yellowV.backgroundColor = [UIColor yellowColor];
[self.view addSubview:_yellowV];
//注意translatesAutoresizingMaskIntoConstraints 一定要设置为 NO
self.blueV.translatesAutoresizingMaskIntoConstraints = NO;
self.yellowV.translatesAutoresizingMaskIntoConstraints = NO;
//views
NSDictionary * views = NSDictionaryOfVariableBindings(_blueV,_yellowV);
//metres
NSDictionary * metres = @{@"readViewW":@100,@"leftArglin":@50,@"rightArglin":@50};
//水平方向的约束
NSArray * HContraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-leftArglin-[_blueV(readViewW)]-11-[_yellowV]-rightArglin-|"
options:0
metrics:metres
views:views];
//垂直方向的约束
NSArray * VContraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-20-[_blueV(50)]-20-[_yellowV(==_blueV)]"
options:0
metrics:metres
views:views];
//添加约束
[self.view addConstraints:HContraints];
[self.view addConstraints:VContraints];
}
5、举个例子
例子1: H:|-20-[_blueV(50)]-11-[_yellowV(50)]-20-|
分开讲解:
1)H:| -20-水平方向的布局是从屏幕的左侧20开始
2)[_blueV(50)]代表_blueV的宽度是50
3)-11-表示距离下一个控件的距离是11
4)[_yellowV(50)]代表_yellowV的宽度是50
5)-20-|表示距离屏幕右侧为20