参考自以下文章:
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层次布局。