自动布局之-NSLayoutConstraint

Posted Kingdev

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自动布局之-NSLayoutConstraint相关的知识,希望对你有一定的参考价值。

AutoLayout概念是苹果自ios6开始引入的概念。
目前为止,实现自动布局技术选型方面也可以使用xib和storyboard。在开发过程中通常登录、注册等变动可能性较小的视图,我会采用xib开发,其他页面通常会采用Masonry布局。xib和手码各有优势,视情况而定。
 
关于NSLayoutAttributeLeading和NSLayoutAttributeTrailing,前边和后边并不是总是为左边和右边的,有些国家的前边是右边后边是左边所以这样设定是为了国际化考虑。还有视图基准线NSLayoutAttributeBaseline通常是指视图的底部放文字的地方。
 
使用NSLayoutConstraint之前,我们需要确定一点:为了防止constraint和view本身的autoresizing属性冲突,我们需要设置view的属性:
view.translatesAutoresizingMaskIntoConstraints = NO;

一、UIKit框架提供的自动布局的方法一,详细请看参数介绍:

/**
 设置约束

 @param view1 指定需要添加约束的视图一
 @param attr1 指定视图一需要约束的属性
 @param relation 指定视图一和视图二添加约束的关系
 @param view2 指定视图一依赖关系的视图二;可为nil
 @param attr2 指定视图一所依赖的视图二的属性,若view2=nil,该属性设置 NSLayoutAttributeNotAnAttribute
 @param multiplier 系数   情况一和二为亲测
                 情况一:设置A视图的高度 = A视图高度 * multiplier + constant;此时才会起作用;
                 情况二:设置A视图和其他视图的关系或 toItem=nil,multiplier设置不等于0即可,若等于0会crash;
 @param c 常量
 @return 返回生成的约束对象
 */
+ (instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(nullable id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c;

以上函数设置的约束等价于   view1.att1 =(以等号举栗子,relation可> < ≥≤)view2.attr2 * multiplier + c;

简单小需求:随意在控制器中添加一个红色view:

// 设置 redView 的宽 = 100.f * 1.f
    NSLayoutConstraint *redViewWidthConstraint =
    [NSLayoutConstraint constraintWithItem:self.redView
                                 attribute:NSLayoutAttributeWidth
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:nil
                                 attribute:NSLayoutAttributeNotAnAttribute
                                multiplier:1.f
                                  constant:100.f];
    // 设置 redView 的高 = 100.f * 1.f
    NSLayoutConstraint *redViewHeightConstraint =
    [NSLayoutConstraint constraintWithItem:self.redView
                                 attribute:NSLayoutAttributeHeight
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:nil
                                 attribute:NSLayoutAttributeNotAnAttribute
                                multiplier:1.f
                                  constant:100.f];
    // 设置 redView 的前面(左边) = self.view.leading + 20.f
    NSLayoutConstraint *redViewleadingConstraint =
    [NSLayoutConstraint constraintWithItem:self.redView
                                 attribute:NSLayoutAttributeLeading
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:self.view
                                 attribute:NSLayoutAttributeLeading
                                multiplier:1.f
                                  constant:20.f];
    
    // 设置 redView 的顶部
    NSLayoutConstraint *redViewTopConstraint =
    [NSLayoutConstraint constraintWithItem:self.redView
                                 attribute:NSLayoutAttributeTop
                                 relatedBy:NSLayoutRelationEqual
                                    toItem:self.view
                                 attribute:NSLayoutAttributeTop
                                multiplier:1.f
                                  constant:30.f];
    [self.view addConstraint:redViewWidthConstraint];
    [self.view addConstraint:redViewHeightConstraint];
    [self.view addConstraint:redViewleadingConstraint];
    [self.view addConstraint:redViewTopConstraint];

 

小注:
1、关于参数  multiplier 
?举个栗子??:
     [NSLayoutConstraint constraintWithItem:aView
     attribute:NSLayoutAttributeHeight
     relatedBy:NSLayoutRelationEqual
     toItem:aView
     attribute:NSLayoutAttributeWidth
     multiplier:2.f
     constant:100.f];
     等价于  aView的高 = aView的宽 * 2.f + 100.f;

 

2、?本来想逃懒,下面的写法,经过我实验是错误的

     [NSLayoutConstraint constraintWithItem:self.redView
     attribute:NSLayoutAttributeWidth | NSLayoutAttributeHeight
     relatedBy:NSLayoutRelationEqual
     toItem:nil
     attribute:NSLayoutAttributeNotAnAttribute
     multiplier:1.f
     constant:100.f];

 

二、UIKit框架提供的自动布局的方法二,VFL语言来实现自动布局:

/**
 Description

 @param format VFL语句,举个栗子:@"H:|-[_redView]-padding-|"
 @param opts 枚举参数,默认写0
 @param metrics 字典,key值为VFL语句中的变量 padding,value为指定的值: @{@"padding" : @50}
 @param views VFL语句中使用到的视图
 */

+ (NSArray<__kindof NSLayoutConstraint *> *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(nullable NSDictionary<NSString *,id> *)metrics views:(NSDictionary<NSString *, id> *)views;
举个栗子:
NSArray *constraints1 =
    [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_redView]-padding-|"
                                            options:0
                                            metrics:@{@"padding" : @50}
                                              views:NSDictionaryOfVariableBindings(_redView)];
    NSArray *constraint2 =
    [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-height-[_redView(height)]"
                                            options:0
                                            metrics:@{@"height" : @20}
                                              views:NSDictionaryOfVariableBindings(_redView)];
    [self.view addConstraints:constraints1];
    [self.view addConstraints:constraint2];

 

关于UILabel自动布局,需要注意的是若label多行显示,可通过设置numberOfLines:

UILabel *label = [[UILabel alloc] init];
    label.translatesAutoresizingMaskIntoConstraints = NO;
    label.text = @"Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~Label~~";
    label.textColor = [UIColor blackColor];
    label.backgroundColor = [UIColor redColor];
    label.numberOfLines = 0;
    [self.view addSubview:label];
    
    NSArray *labelConstraintsH =
    [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-20-[label]-20-|"
                                            options:0
                                            metrics:nil
                                              views:NSDictionaryOfVariableBindings(label)];
    NSArray *labelConstraintsV =
    [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-30-[label]"
                                            options:0
                                            metrics:nil
                                              views:NSDictionaryOfVariableBindings(label)];
    [self.view addConstraints:labelConstraintsH];
    [self.view addConstraints:labelConstraintsV];

注意:
     1、VFL语句中具体浮点型不可以使用 56.f 诸如此类,会crash;
     2、VFL语句中的视图,不要使用self.xxx属性,而要使用变量_xxx,会crash
     3、addConstraint之前,必须保证subView已拥有superView
     4、视图的 translatesAutoresizingMaskIntoConstraints 必须设置为NO,
 
 
结语:项目开发过程中,通常使用的是Masonry\SnapKit自动布局的三方库,简单高效。校之frame布局,自动布局更适合业务拓展。 

以上是关于自动布局之-NSLayoutConstraint的主要内容,如果未能解决你的问题,请参考以下文章

iOS开发NSLayoutConstraint代码自动布局

激活/停用自动布局 NSLayoutConstraint

iOS原生自动布局NSLayoutConstraint

未设置 NIB“使用自动布局”时,我可以使用 NSLayoutConstraint 吗?

IOS开发之自动布局框架设计

自动布局警告:将尝试通过在 CollectionView 中打破约束 <NSLayoutConstraint 来恢复