iOS 自动布局总结

参考自以下文章:

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里面选取

metricsnil;一般为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(自动布局过程介绍)

与使用springs and struts(autoresizingMask)比较,Auto layout在view显示之前,多引入了两个步骤:updating constraints 和laying out views。每一个步骤都依赖于上一个。display依赖layout,而layout依赖updating constraints。 updating constraints->layout->display


第一步: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层次布局。



原文地址:https://www.cnblogs.com/AbeDay/p/5026961.html