参考自以下文章:
http://blog.csdn.net/ysy441088327/article/details/12558097
http://blog.csdn.net/zhouleizhao/article/details/31741711
http://blog.csdn.net/dongbaojun_ios/article/details/12566529
首先介绍自动布局的概念:
Auto Layout翻译过来意思是自动布局,通过内定的Constraint(约束)和各项条件来计算出合理的布局.而这个合理的布局,符合我们的的预期和意图.
将我们想象中的结果展现出来.Constraint的设定非常灵活,实现一种布局的方法可以通过多Constraint套来完成.
下面是在IB中添加自动布局的介绍:
使用editor中的约束条件:
这四个是约束条件的设计创建选择框
下面来逐个介绍:
1. Align(校准)
从上到下依次是:
左边界-右边界-顶部-底部-中心垂线-中心水平线-底线-中心垂线约束-中心水平线约束
2. resolve auto layout issues(决定布局问题)
这里有两个子框架一个是作用于选中的视图,还有一个是对于全部的视图。
对于选中的视图: 更新框架-更新约束-添加新的约束-调整成推荐约束-清空约束
对于全部的视图:是和上面一样的选项,但是不同的是它作用于所有的视图。
3. Pin(大头针)
从上到下这些图标的功能如下:
固定view自身宽度-固定view自身高度-固定两个view之间的水平空间-固定两个view之间的垂直空间-固定两个view之间的水平空间-固定view与父视图的左边界距离-固定view与父视图的右边界距离-固定view与父视图的上边界距离-固定view与父视图的下边界距离-使两个view自身的宽度相等-使两个view自身的高度相等
观察一下界面预览右下角,有一排如下图这样的按钮:
这些功能分别如下图中描述的那样:
此方法是比较有用的,我们可以使用它来定义约束,而且约束的形式比较自由。当我们面领着4英寸和4.7英寸的大小变化时,我们可以使用采取这个操作:
在这里可以建立它对于中心线的相对位置,因为中性线的位置是不会变的。
当然,如果你还用详细的设置一个约束的条件,那么我们应该点击进入详细情况编写。
二:下面为代码实现自动布局设置
首先使用第一种设置约束的方式:
[NSLayoutConstraint constraintWithItem:(id)item attribute:(NSLayoutAttribute)attribute relatedBy:(NSLayoutRelation)relation toItem:(id)otherItem attribute:(NSLayoutAttribute)otherAttribute multiplier:(CGFloat)multiplier constant:(CGFloat)constant] //这个函数的对照公式为: //view1.attr1 <relation> view2.attr2 * multiplier + constant
函数作用:
使用了这个函数来为view1添加了一个约束,这个约束是以view2的属性为依据的。
(注意:如果你想设置的约束里不需要第二个view,要将第四个参数设为nil,第五个参数设为NSLayoutAttributeNotAnAttribute)
[NSLayoutConstraint constraintWithItem:view1 attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:view2 attribute:NSLayoutAttributeRight multiplier:1 constant:10] //翻译过来就是:(view1的左侧)的位置 = (view2的右侧+10个点)的位置
附视图的属性和关系的值:
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是左边
使用第二种设置约束的方式:
NSDictionary *viewsDic = NSDictionaryOfVariableBindings(deleteButton,cancelButton,nextButton); NSArray *constraints = nil; constraints = [NSLayoutConstraint constraintsWithVisualFormat: <span style="white-space:pre"> </span>@"H:|-25-[deleteButton(==cancelButton@700)]-(>=8)-[cancelButton(140)]-[nextButton(nextButtonWidth)]-rectY-|"//水平 可视化格式语言 <span style="white-space:pre"> </span>options:NSLayoutFormatAlignAllTop //对齐功能 <span style="white-space:pre"> </span>metrics:@{@"rectY":@5,@"nextButtonWidth":@30}//指标参数 <span style="white-space:pre"> </span>views:viewsDic];//参与约束的对象字典 [self.view addConstraints:constraints]; constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[nextButton]-|" //垂直 可视化格式语言 <span style="white-space:pre"> </span>options:0 //无条件 <span style="white-space:pre"> </span>metrics:nil//不带指标参数 <span style="white-space:pre"> </span>views:viewsDic];//参与约束的对象字典 [self.view addConstraints:constraints];
函数介绍:
关于constraintsWithVisualFormat:函数介绍:
constraintsWithVisualFormat:参数为NSString型,指定Contsraint的属性,是垂直方向的限定还是水平方向的限定,参数定义一般如下:
V:|-(>=XXX):表示垂直方向上相对于SuperView大于、等于、小于某个距离
若是要定义水平方向,则将V:改成H:即可
在接着后面-[]中括号里面对当前的View/控件的高度/宽度进行设定;
options:字典类型的值;这里的值一般在系统定义的一个enum里面选取
metrics:nil;一般为nil,参数类型为NSDictionary,从外部传入 //衡量标准
views:就是上面所加入到NSDictionary中的绑定的View
在这里要注意的是AddConstraints 和 AddConstraint之间的区别,一个添加的参数是NSArray,一个是NSLayoutConstraint
使用规则
|: 表示父视图
-:表示距离
V: :表示垂直
H: :表示水平
>= :表示视图间距、宽度和高度必须大于或等于某个值
<= :表示视图间距、宽度和高度必须小宇或等于某个值
== :表示视图间距、宽度或者高度必须等于某个值
@ :>=、<=、== 限制 最大为 1000
下面是一个使用代码来实现界面约束的代码实例:
if(floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) { self.edgesForExtendedLayout = UIRectEdgeNone; } //自动布局 //正常的创建按钮,但不用设置按钮的Frame属性 UIButton * leftButton = [UIButton buttonWithType:UIButtonTypeSystem]; leftButton.layer.borderWidth = 2.0; leftButton.layer.borderColor = [UIColor blackColor].CGColor; [leftButton setTitle:@"左" forState:UIControlStateNormal]; [self.view addSubview:leftButton]; UIButton * rightButton = [UIButton buttonWithType:UIButtonTypeSystem]; rightButton.layer.borderWidth = 2.0; rightButton.layer.borderColor = [UIColor blackColor].CGColor; [rightButton setTitle:@"右" forState:UIControlStateNormal]; [self.view addSubview:rightButton]; //将自适应向布局约束的转化关掉(根据情况有时需要有时不需要) [leftButton setTranslatesAutoresizingMaskIntoConstraints:NO]; [rightButton setTranslatesAutoresizingMaskIntoConstraints:NO]; //创建一个存放约束的数组 NSMutableArray * tempConstraints = [NSMutableArray array]; /* 创建水平方向的约束:在水平方向,leftButton距离父视图左侧的距离为80,leftButton宽度为60,rightButton和leftButton之间的距离为30,rightButton宽60 */ [tempConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-80-[leftButton(==60)]-30-[rightButton(==60)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(leftButton,rightButton)]]; /* 创建竖直方向的约束:在竖直方向上,leftButton距离父视图顶部30,leftButton高度30 */ [tempConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-30-[leftButton(==30)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(leftButton)]]; /* 竖直方向的约束:在竖直方向上,rightButton距离其父视图顶部30,高度与leftButton的高度相同 */ [tempConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-30-[rightButton(==leftButton)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(rightButton,leftButton)]]; //给视图添加约束 [self.view addConstraints:tempConstraints];
Layout Process(自动布局过程介绍)
第一步:updating constraints,被称为测量阶段,其从下向上(from subview to super view),为下一步layout准备信息。可以通过调用方法 setNeedUpdateConstraints 去触发此步。constraints的改变也会自动的触发此步。但是,当你自定义view的时候,如果一些改变可能会影响到布局的时候,通常需要自己去通知Auto layout。说到自定义view了,通常可以重写updateConstraints方法,在其中可以添加view需要的局部的contraints。
第二步:layout,其从上向下(from super view to subview),此步主要应用上一步的信息去设置view的center和bounds。可以通过调用setNeedsLayout去触发此步骤,此方法不会立即应用layout。如果想要系统立即的更新layout,可以调用layoutIfNeeded。另外,自定义view可以重写方法layoutSubViews来在layout的工程中得到更多的控制。
第三步:display,此步时把view渲染到屏幕上,它与你是否使用Auto layout无关,其操作是从上向下(from super view to subview),通过调用setNeedsDisplay触发,
因为每一步都依赖前一步,因此一个display可能会触发layout,当有任何layout没有被处理的时候,同理,layout可能会触发updating constraints,当constraint system更新改变的时候。
需要注意的是,这三步不是单向的,constraint-based layout是一个迭代的过程,layout过程中,可能去改变constraints,有一次触发updating constraints,进行一轮layout过程。这可以被用来创建高级的自定义视图布局,但是如果你每一次调用自定义layoutSubviews都会导致另一个布局传递,那么你将会陷入一个无限循环中。如图:
setNeedsLayout和layoutIfNeeded方法介绍
- (void)setNeedsLayout 此方法会将view当前的layout设置为无效的,并在下一个upadte cycle里去触发layout更新。 - (void)layoutIfNeeded 使用此方法强制立即进行layout,从当前view开始,此方法会遍历整个view层次(包括superviews)请求layout。因此,调用此方法会强制整个view层次布局。