美文网首页iOS专题
iOS基础(一) - AutoLayout入门

iOS基础(一) - AutoLayout入门

作者: 一剑孤城 | 来源:发表于2016-12-08 10:38 被阅读281次

    前言

    苹果在iOS6就出了自动化布局(NSLayoutConstraint),很多第三方库就是基于原生的类的封装,比如:Masonry等。在iOS9的时候,加入了NSLayoutAnchor这个类,大大简化了原生的自动化布局。下面就从NSLayoutConstrint这个类说起。

    1.NSLayoutConstraint

    首先,我们需要了解到一个基本常识,就是多少约束可以最终确定一个物体的位置。我们绘画的时候会从大概一个点开始画,然后以这个点作为参照,逐步绘制整个画面。同理,确定一个物体,也先要确定一个参考点,这里称为初始点,学过数学的坐标系的同学都清楚,在平面坐标系,确定一个点需要横坐标和纵坐标,而作为一个添加在父控件的子控件,初始点的横坐标就是距离父控件的左边间距或者右边间距,纵坐标就是距离父控件的顶部间距或者底部间距。初始点确定了,我们开始绘制图形。由于绘制区域都是矩形,所以,在初始点确定之后,只需要宽和高就能绘制出一个完整的矩形。所以,至少需要四个约束,才能最终确定一个物体,两个约束确定一个初始点,两个约束确定宽和高。

    废话不多说,开始进入正题:

    (1)NSLayoutAttributes代表一个约束的字符串,比如:上下左右等等。
    typedef NS_ENUM(NSInteger, NSLayoutAttribute) {
        NSLayoutAttributeLeft = 1,
        NSLayoutAttributeRight,
        NSLayoutAttributeTop,
        NSLayoutAttributeBottom,
        NSLayoutAttributeLeading,
        NSLayoutAttributeTrailing,
        NSLayoutAttributeWidth,
        NSLayoutAttributeHeight,
        NSLayoutAttributeCenterX,
        NSLayoutAttributeCenterY,
        NSLayoutAttributeLastBaseline,
        NSLayoutAttributeBaseline NS_SWIFT_UNAVAILABLE("Use 'lastBaseline' instead") = NSLayoutAttributeLastBaseline,
        
    //iOS8.0以后新增
        NSLayoutAttributeFirstBaseline,
        NSLayoutAttributeLeftMargin,
        NSLayoutAttributeRightMargin,
        NSLayoutAttributeTopMargin,
        NSLayoutAttributeBottomMargin,
        NSLayoutAttributeLeadingMargin,
        NSLayoutAttributeTrailingMargin,
        NSLayoutAttributeCenterXWithinMargins,
        NSLayoutAttributeCenterYWithinMargins,
        
        NSLayoutAttributeNotAnAttribute = 0
    };
    

    NSLayoutAttributeLeft和NSLayoutAttributeLeftMargin的区别:
    NSLayoutAttributeLeft指的是控件的左边,具体来说是控件的最左边;NSLayoutAttributeLeftMargin也是指控件的左边,但是不是最左边,具体距离最左边有多大的Margin和控件的layoutMargins有关。
    苹果官方的描述:

    NSLayoutAttributeLeftMargin: The object's left margin.For UIView objects, the margins are defined by their layoutMargins property.
    

    注:默认是{8,8,8,8},但是如果是viewController的root view则top和bottom的margins为0,左右margins可能是16或者20,这取决于当前的view尺寸,并且不能修改。

    (2)NSLayoutRelation可以理解为一个比较符(<=,=,>=)
    typedef NS_ENUM(NSInteger, NSLayoutRelation) {
        NSLayoutRelationLessThanOrEqual = -1,    //<=
        NSLayoutRelationEqual = 0,               //=
        NSLayoutRelationGreaterThanOrEqual = 1,  //>=
    }
    

    该选项是用于两个约束的比较,例如:view2的左边距离view1的右边20个点。(view2.left = view1.right * 1 + 20)

    (3)UILayoutPriority优先级
    static const UILayoutPriority UILayoutPriorityRequired NS_AVAILABLE_IOS(6_0) = 1000; // A required constraint.  Do not exceed this.
    static const UILayoutPriority UILayoutPriorityDefaultHigh NS_AVAILABLE_IOS(6_0) = 750; // This is the priority level with which a button resists compressing its content.
    static const UILayoutPriority UILayoutPriorityDefaultLow NS_AVAILABLE_IOS(6_0) = 250; // This is the priority level at which a button hugs its contents horizontally.
    static const UILayoutPriority UILayoutPriorityFittingSizeLevel NS_AVAILABLE_IOS(6_0) = 50; // When you send -[UIView systemLayoutSizeFittingSize:], the size fitting most closely to the target size (the argument) is computed.  UILayoutPriorityFittingSizeLevel is the priority level with which the view wants to conform to the target size in that computation.  It's quite low.  It is generally not appropriate to make a constraint at exactly this priority.  You want to be higher or lower.
    

    优先级只有在两个约束有冲突的时候才起作用,优先级高的会覆盖优先级低的,最高的优先级为1000。

    (4)约束简单入门

    🌰 一:简单为两个view添加约束
    效果图:


    Demo1.PNG

    代码:

    UIView *leftView = [UIView new];  
    leftView.translatesAutoresizingMaskIntoConstraints = NO;
    leftView.backgroundColor = [UIColor blueColor];
    [self.view addSubview: leftView];
        
    UIView *rightView = [UIView new];
    rightView.translatesAutoresizingMaskIntoConstraints = NO;
    rightView.backgroundColor = [UIColor greenColor];
    [self.view addSubview: rightView];
        
    //添加约束方式一
    //调用父控件添加约束的函数,添加子控件约束
    //控件约束对象必须是拥有同一父控件的子控件或者是父控件
    NSLayoutConstraint *leftViewLeftConstraint = [NSLayoutConstraint constraintWithItem: leftView attribute: NSLayoutAttributeLeft relatedBy: NSLayoutRelationEqual toItem: self.view attribute: NSLayoutAttributeLeft multiplier: 1.0 constant: 20];
    NSLayoutConstraint *leftViewTopConstraint = [NSLayoutConstraint constraintWithItem: leftView attribute: NSLayoutAttributeTop relatedBy: NSLayoutRelationEqual toItem: self.view attribute: NSLayoutAttributeTop multiplier: 1.0 constant: 60];
    NSLayoutConstraint *leftViewWidth = [NSLayoutConstraint constraintWithItem: leftView attribute: NSLayoutAttributeWidth relatedBy: NSLayoutRelationEqual toItem: nil attribute: NSLayoutAttributeNotAnAttribute multiplier: 1.0 constant: 80];
    NSLayoutConstraint *leftViewHeight = [NSLayoutConstraint constraintWithItem: leftView attribute: NSLayoutAttributeHeight relatedBy: NSLayoutRelationEqual toItem: nil attribute: NSLayoutAttributeNotAnAttribute multiplier: 1.0 constant: 80];
    [self.view addConstraints: @[leftViewLeftConstraint, leftViewTopConstraint, leftViewWidth, leftViewHeight]];
        
    NSLayoutConstraint *rightViewLeftConstraint = [NSLayoutConstraint constraintWithItem: rightView attribute: NSLayoutAttributeLeft relatedBy: NSLayoutRelationEqual toItem: leftView attribute: NSLayoutAttributeRight multiplier: 1.0 constant: 20];
    NSLayoutConstraint *rightViewTopConstraint = [NSLayoutConstraint constraintWithItem: rightView attribute: NSLayoutAttributeTop relatedBy: NSLayoutRelationEqual toItem: self.view attribute: NSLayoutAttributeTop multiplier: 1.0 constant: 60];
    NSLayoutConstraint *rightViewWith = [NSLayoutConstraint constraintWithItem: rightView attribute: NSLayoutAttributeWidth relatedBy: NSLayoutRelationEqual toItem: leftView attribute: NSLayoutAttributeWidth multiplier: 1.0 constant: 0];
    NSLayoutConstraint *rightViewHeight = [NSLayoutConstraint constraintWithItem: rightView attribute: NSLayoutAttributeHeight relatedBy: NSLayoutRelationEqual toItem: leftView attribute: NSLayoutAttributeHeight multiplier: 1.0 constant: 0];
    [self.view addConstraints: @[rightViewLeftConstraint, rightViewTopConstraint, rightViewWith, rightViewHeight]];
    
    //添加约束方式二
    //调用NSLayoutConstraint的类方法使约束生效(iOS8以后)
    [NSLayoutConstraint activateConstraints: @[leftViewLeftConstraint, leftViewTopConstraint, leftViewWidth, leftViewHeight, rightViewLeftConstraint, rightViewTopConstraint, rightViewWith, rightViewHeight]];
    
    //添加约束方式三
    //直接将约束的active设置为YES,使约束生效(iOS8以后)
    //并且方式三比方式二更为高效,苹果官方推荐用法
    [NSLayoutConstraint constraintWithItem: leftView attribute: NSLayoutAttributeLeft relatedBy: NSLayoutRelationEqual toItem: self.view attribute: NSLayoutAttributeLeft multiplier: 1.0 constant: 20].active = YES;
    
    //Tips:建议controller约束写在updateViewConstraints里面,view约束写在updateConstraints里面。
    

    🌰 二:神奇的视图二等分
    效果图:


    二等分.PNG
    UIView *leftView = [[UIView alloc] init];
    leftView.backgroundColor = [UIColor greenColor];
    leftView.translatesAutoresizingMaskIntoConstraints = NO;
        
    UIView *rightView = [[UIView alloc] init];
    rightView.backgroundColor = [UIColor blueColor];
    rightView.translatesAutoresizingMaskIntoConstraints = NO;
        
    [self.view addSubview: leftView];
    [self.view addSubview: rightView];
    
    //首先,设置leftView的约束
    [NSLayoutConstraint constraintWithItem: leftView attribute: NSLayoutAttributeTop relatedBy: NSLayoutRelationEqual toItem: self.view attribute: NSLayoutAttributeTop multiplier: 1.0 constant: 84].active = YES;    //leftView顶部距离父控件84个点
    [NSLayoutConstraint constraintWithItem: leftView attribute: NSLayoutAttributeLeft relatedBy: NSLayoutRelationEqual toItem: self.view attribute: NSLayoutAttributeLeft multiplier: 1.0 constant: 20].active = YES;    //leftView左边距离父控件20个点
    [NSLayoutConstraint constraintWithItem: leftView attribute: NSLayoutAttributeHeight relatedBy: NSLayoutRelationEqual toItem: nil attribute: NSLayoutAttributeNotAnAttribute multiplier: 1.0 constant: 200].active = YES;    //leftView的height=200,这里宽在后面设置
    
    //其次,设置rightView的约束
    [NSLayoutConstraint constraintWithItem: rightView attribute: NSLayoutAttributeTop relatedBy: NSLayoutRelationEqual toItem: leftView attribute: NSLayoutAttributeTop multiplier: 1.0 constant: 0].active = YES;    //rightView顶部和leftView对齐
    [NSLayoutConstraint constraintWithItem: rightView attribute: NSLayoutAttributeHeight relatedBy: NSLayoutRelationEqual toItem: leftView attribute: NSLayoutAttributeHeight multiplier: 1.0 constant: 0].active = YES;    //rightView的高和leftView的高对等
    [NSLayoutConstraint constraintWithItem: rightView attribute: NSLayoutAttributeRight relatedBy: NSLayoutRelationEqual toItem: self.view attribute: NSLayoutAttributeRight multiplier: 1.0 constant: -20].active = YES;    //rightView的右边距离父控件20个点
    
    //最后,二等分的魔法就要开始了
    //leftView和rightView都添加了三个约束,从刚开始,我就提到,至少需要四个约束,leftView和rightView都缺少了一个宽的约束,所以,下面就是为这两个view添加上宽的约束
    [NSLayoutConstraint constraintWithItem: rightView attribute: NSLayoutAttributeWidth relatedBy: NSLayoutRelationEqual toItem: leftView attribute: NSLayoutAttributeWidth multiplier: 1.0 constant: 0].active = YES;    //使leftView的width和right的width想等
    [NSLayoutConstraint constraintWithItem: leftView attribute: NSLayoutAttributeRight relatedBy: NSLayoutRelationEqual toItem: rightView attribute: NSLayoutAttributeLeft multiplier: 1.0 constant: -20].active = YES;    //leftView的右边距离rightView的左边20个点
    
    //可以把leftView和rightView看作一个整体,那么这个整体就是left=super.left+20,right=super.right-20,top=super.top+20,height=200,四个约束可以确定一个view的位置
    //这时候来看内部的约束,首先,leftView.width=rightView.width,leftView.right=rightView.left-20,所以,leftView和rightView等分
    

    🌰 三:约束动画(这里涉及到约束优先级)
    效果动图:


    autoLayoutAnimate.gif
    //添加三个view
    _redView = [UIView new];
    _redView.backgroundColor = [UIColor redColor];
    _redView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview: _redView];
        
    _purpleView = [UIView new];
    _purpleView.backgroundColor = [UIColor purpleColor];
    _purpleView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview: _purpleView];
        
    _grayView = [UIView new];
    _grayView.backgroundColor = [UIColor grayColor];
    _grayView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview: _grayView];
        
    //设置三个view的约束
    NSLayoutConstraint *redLeft = [NSLayoutConstraint constraintWithItem: _redView attribute: NSLayoutAttributeLeft relatedBy: NSLayoutRelationEqual toItem: self.view attribute: NSLayoutAttributeLeft multiplier: 1.0 constant: 20];
    NSLayoutConstraint *redTop = [NSLayoutConstraint constraintWithItem: _redView attribute: NSLayoutAttributeTop relatedBy: NSLayoutRelationEqual toItem: self.view attribute: NSLayoutAttributeTop multiplier: 1.0 constant: 84];
    NSLayoutConstraint *redHeight = [NSLayoutConstraint constraintWithItem: _redView attribute: NSLayoutAttributeHeight relatedBy: NSLayoutRelationEqual toItem: nil attribute: NSLayoutAttributeNotAnAttribute multiplier: 1.0 constant: 60];
    NSLayoutConstraint *redWidth = [NSLayoutConstraint constraintWithItem: _redView attribute: NSLayoutAttributeWidth relatedBy: NSLayoutRelationEqual toItem: nil attribute: NSLayoutAttributeNotAnAttribute multiplier: 1.0 constant: 60];
    [self.view addConstraints: @[redLeft, redTop, redHeight, redWidth]];
        
    NSLayoutConstraint *purpleLeft = [NSLayoutConstraint constraintWithItem: _purpleView attribute: NSLayoutAttributeLeft relatedBy: NSLayoutRelationEqual toItem: _redView attribute: NSLayoutAttributeRight multiplier: 1.0 constant: 20];
    NSLayoutConstraint *purpleTop = [NSLayoutConstraint constraintWithItem: _purpleView attribute: NSLayoutAttributeTop relatedBy: NSLayoutRelationEqual toItem: _redView attribute: NSLayoutAttributeTop multiplier: 1.0 constant: 0];
    NSLayoutConstraint *purpleHeight = [NSLayoutConstraint constraintWithItem: _purpleView attribute: NSLayoutAttributeHeight relatedBy: NSLayoutRelationEqual toItem: _redView attribute: NSLayoutAttributeHeight multiplier: 1.0 constant: 0];
    NSLayoutConstraint *purpleWidth = [NSLayoutConstraint constraintWithItem: _purpleView attribute: NSLayoutAttributeWidth relatedBy: NSLayoutRelationEqual toItem: _redView attribute: NSLayoutAttributeWidth multiplier: 1.0 constant: 0];
    _purpleConstraints = @[purpleLeft, purpleTop, purpleHeight, purpleWidth];[self.view addConstraints: _purpleConstraints];
        
    NSLayoutConstraint *grayLeft = [NSLayoutConstraint constraintWithItem: _grayView attribute: NSLayoutAttributeLeft relatedBy: NSLayoutRelationEqual toItem: _purpleView attribute: NSLayoutAttributeRight multiplier: 1.0 constant: 20];
    NSLayoutConstraint *grayTop = [NSLayoutConstraint constraintWithItem: _grayView attribute: NSLayoutAttributeTop relatedBy: NSLayoutRelationEqual toItem: _redView attribute: NSLayoutAttributeTop multiplier: 1.0 constant: 0];
    NSLayoutConstraint *grayHeight = [NSLayoutConstraint constraintWithItem: _grayView attribute: NSLayoutAttributeHeight relatedBy: NSLayoutRelationEqual toItem: _redView attribute: NSLayoutAttributeHeight multiplier: 1.0 constant: 0];
    NSLayoutConstraint *grayWidth = [NSLayoutConstraint constraintWithItem: _grayView attribute: NSLayoutAttributeWidth relatedBy: NSLayoutRelationEqual toItem: _redView attribute: NSLayoutAttributeWidth multiplier: 1.0 constant: 0];
    _grayConstraints = @[grayLeft, grayTop, grayHeight, grayWidth];
    [self.view addConstraints: _grayConstraints];
        
    //最重要的一个约束,将第三个灰色的view另外添加多一条约束grayView.left=redView.right+20(@250),优先级设置比默认的低,这样在和grayView.left=purpleView.right+20(@1000)约束有冲突的时候,系统会忽略优先级低的约束,所以,刚开始显示是红紫灰
    _animateConstraint = [NSLayoutConstraint constraintWithItem: _grayView attribute: NSLayoutAttributeLeft relatedBy: NSLayoutRelationEqual toItem: _redView attribute: NSLayoutAttributeRight multiplier: 1.0 constant: 20];
    _animateConstraint.priority = UILayoutPriorityDefaultLow;
    [self.view addConstraint: _animateConstraint];
    
    //触发动画
    //将中间紫色的view移除
    //标记页面刷新,并立刻刷新
    //这时候由于第二个view被移除了,所以优先级低的约束就起作用了
    [_purpleView removeFromSuperview];
    [UIView animateWithDuration: 0.2 animations:^{
        [self.view setNeedsLayout];
        [self.view layoutIfNeeded];
    }];
    

    2.VFL

    VFL其实也是对NSLayoutConstraint的封装,更为具像化,目的就是为了简化自动化布局。在我看来,入门有点复杂,入门后就比较简单。呵呵哒,具体见仁见智。

    (1)VFL语法:
    表达式 功能
    H: 水平方向
    V: 垂直方向
    [view] 视图
    l 父控件边界
    >=,==,<= 约束不等式
    - 间隙,连接视图和约束,视图和视图
    @value 优先级
    /**
     *  VFL创建约束
     *
     *
     *  @param format   传入VFL格式的约束字符串,例如:@“H:|-20-[leftView(50)]”,水平方向上,leftView左边与父控件左边相距20,redView宽度为50
     *
     *  @param opts     对齐方式
     *
     *  @param metrics  匹配format里面相同的key的字典,比如:@{@"margin": 20}, @"H:|-margin-[leftView(50)]"等同于@“H:|-20-[leftView(50)]”;
     *
     *  @param views    一个字典,包含format里面的view,比如:format: @“H:|-20-[leftView(50)]”,metrics: @{@"leftView": leftView}
     *
     *  @return 返回包含一系列约束的数组
     *
     */
    
    + (NSArray<__kindof NSLayoutConstraint *> *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(nullable NSDictionary<NSString *,id> *)metrics views:(NSDictionary<NSString *, id> *)views;
    
    //options
    typedef NS_OPTIONS(NSUInteger, NSLayoutFormatOptions) {
        NSLayoutFormatAlignAllLeft = (1 << NSLayoutAttributeLeft),    //所有控件左边缘对齐
        NSLayoutFormatAlignAllRight = (1 << NSLayoutAttributeRight),    
        NSLayoutFormatAlignAllTop = (1 << NSLayoutAttributeTop),    //所有控件顶部边缘对齐
        NSLayoutFormatAlignAllBottom = (1 << NSLayoutAttributeBottom),    
        NSLayoutFormatAlignAllLeading = (1 << NSLayoutAttributeLeading),    //相当于NSLayoutFormatAlignAllLeft
        NSLayoutFormatAlignAllTrailing = (1 << NSLayoutAttributeTrailing),    //相当于NSLayoutFormatAlignAllRight
        NSLayoutFormatAlignAllCenterX = (1 << NSLayoutAttributeCenterX),
        NSLayoutFormatAlignAllCenterY = (1 << NSLayoutAttributeCenterY),
        NSLayoutFormatAlignAllLastBaseline = (1 << NSLayoutAttributeLastBaseline),
        NSLayoutFormatAlignAllBaseline NS_SWIFT_UNAVAILABLE("Use 'alignAllLastBaseline' instead") = NSLayoutFormatAlignAllLastBaseline,
        NSLayoutFormatAlignAllFirstBaseline NS_ENUM_AVAILABLE_IOS(8_0) = (1 << NSLayoutAttributeFirstBaseline),
        
        NSLayoutFormatAlignmentMask = 0xFFFF,
        
        /* choose only one of these three
         */
        NSLayoutFormatDirectionLeadingToTrailing = 0 << 16, // default
        NSLayoutFormatDirectionLeftToRight = 1 << 16,
        NSLayoutFormatDirectionRightToLeft = 2 << 16,  
        
        NSLayoutFormatDirectionMask = 0x3 << 16,  
    };
    
    (2)重写NSLayoutConstraint简单入门的例子

    🌰 一:简单为两个view添加约束

    UIView *leftView = [UIView new];
    leftView.translatesAutoresizingMaskIntoConstraints = NO;
    leftView.backgroundColor = [UIColor blueColor];
    [self.view addSubview: leftView];
        
    UIView *rightView = [UIView new];
    rightView.translatesAutoresizingMaskIntoConstraints = NO;
    rightView.backgroundColor = [UIColor greenColor];
    [self.view addSubview: rightView];
        
    NSString *hConstraint = @"H:|-20-[leftView(80)]-20-[rightView(==leftView)]";
    NSString *vConstraint = @"V:|-84-[leftView(80)]";
    NSArray *hConstraints = [NSLayoutConstraint constraintsWithVisualFormat: hConstraint options: NSLayoutFormatAlignAllTop|NSLayoutFormatAlignAllBottom metrics: nil views: NSDictionaryOfVariableBindings(leftView, rightView)];
    NSArray *vConstraints = [NSLayoutConstraint constraintsWithVisualFormat: vConstraint options: NSLayoutFormatAlignAllTop metrics: nil views: NSDictionaryOfVariableBindings(leftView, rightView)];
    [self.view addConstraints: hConstraints];
    [self.view addConstraints: vConstraints];
    

    🌰 二:神奇的视图二等分

    UIView *leftView = [[UIView alloc] init];
    leftView.backgroundColor = [UIColor greenColor];
    leftView.translatesAutoresizingMaskIntoConstraints = NO;
        
    UIView *rightView = [[UIView alloc] init];
    rightView.backgroundColor = [UIColor blueColor];
    rightView.translatesAutoresizingMaskIntoConstraints = NO;
        
    [self.view addSubview: leftView];
    [self.view addSubview: rightView];
        
    NSString *hConstraint = @"H:|-margin-[leftView]-margin-[rightView(==leftView)]-20-|";
    NSString *vConstraint = @"V:|-margin-[leftView(200)]";
        
    NSArray *hConstraints = [NSLayoutConstraint constraintsWithVisualFormat: hConstraint options: NSLayoutFormatAlignAllTop | NSLayoutFormatAlignAllBottom metrics: @{@"margin": @"20"} views: NSDictionaryOfVariableBindings(leftView, rightView)];
    NSArray *vConstraints = [NSLayoutConstraint constraintsWithVisualFormat: vConstraint options: 0 metrics: @{@"margin": @"84"} views: NSDictionaryOfVariableBindings(leftView, rightView)];
    [self.view addConstraints: hConstraints];
    [self.view addConstraints: vConstraints];
    

    🌰 三:约束动画(这里涉及到约束优先级)

    _redView = [UIView new];
    _redView.backgroundColor = [UIColor redColor];
    _redView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview: _redView];
        
    _purpleView = [UIView new];
    _purpleView.backgroundColor = [UIColor purpleColor];
    _purpleView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview: _purpleView];
        
    _grayView = [UIView new];
    _grayView.backgroundColor = [UIColor grayColor];
    _grayView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview: _grayView];
        
    NSString *hConstraint = @"H:|-margin-[_redView(60)]-margin-[_purpleView(==_redView)]-margin-[_grayView(==_redView)]";
    NSString *vConstraint = @"V:|-margin-[_redView(60)]";
    NSString *hConstraint2 = @"H:[_redView(60)]-margin@250-[_grayView(==_redView)]";
        
    NSArray *hConstraints = [NSLayoutConstraint constraintsWithVisualFormat: hConstraint options: NSLayoutFormatAlignAllTop|NSLayoutFormatAlignAllBottom metrics: @{@"margin": @20} views: NSDictionaryOfVariableBindings(_redView, _purpleView, _grayView)];
    NSArray *vConstraints = [NSLayoutConstraint constraintsWithVisualFormat: vConstraint options: 0 metrics: @{@"margin": @84} views: NSDictionaryOfVariableBindings(_redView, _purpleView, _grayView)];
    NSArray *hConstraints2 = [NSLayoutConstraint constraintsWithVisualFormat: hConstraint2 options: NSLayoutFormatAlignAllTop|NSLayoutFormatAlignAllBottom metrics: @{@"margin": @20} views: NSDictionaryOfVariableBindings(_redView, _grayView)];
    [self.view addConstraints: hConstraints];
    [self.view addConstraints: vConstraints];
    [self.view addConstraints: hConstraints2];
    
    //触发动画
    [_purpleView removeFromSuperview];
    [UIView animateWithDuration: 0.2 animations:^{
        [self.view setNeedsLayout];
        [self.view layoutIfNeeded];
    }];
    

    另外添加一个🌰 ,就是两个view不等高的情况:
    效果图:


    例子四.PNG
    //这里利用优先级不同来解决问题
    UIView *leftView = [UIView new];
    leftView.translatesAutoresizingMaskIntoConstraints = NO;
    leftView.backgroundColor = [UIColor blueColor];
    [self.view addSubview: leftView];
        
    UIView *rightView = [UIView new];
    rightView.translatesAutoresizingMaskIntoConstraints = NO;
    rightView.backgroundColor = [UIColor greenColor];
    [self.view addSubview: rightView];
        
    NSString *hConstraint = @"H:|-20-[leftView(80)]-20-[rightView(==leftView)]";
    NSString *vConstraint = @"V:|-84-[leftView(80@250)]";    //先设置优先级低于默认优先级
    NSString *vConstraint2 = @"V:[rightView(120)]";    //默认优先级1000,会覆盖前面优先级低的约束
    NSArray *hConstraints = [NSLayoutConstraint constraintsWithVisualFormat: hConstraint options: NSLayoutFormatAlignAllTop metrics: nil views: NSDictionaryOfVariableBindings(leftView, rightView)];
    NSArray *vConstraints = [NSLayoutConstraint constraintsWithVisualFormat: vConstraint options: 0 metrics: nil views: NSDictionaryOfVariableBindings(leftView, rightView)];
    NSArray *vConstraints2 = [NSLayoutConstraint constraintsWithVisualFormat: vConstraint2 options: 0 metrics: nil views: NSDictionaryOfVariableBindings(rightView)];
    [self.view addConstraints: hConstraints];
    [self.view addConstraints: vConstraints];
    [self.view addConstraints: vConstraints2];
    

    3.NSLayoutAnchor

    NSLayourAnchor是iOS9之后出来的,总共包含NSLayoutXAxisAnchor,NSLayoutYAxisAnchor以及NSLayoutDimension,分别代表x坐标,y坐标和宽高。

    NSLayoutAnchor属性
    /* Constraint creation conveniences. See NSLayoutAnchor.h for details.
     */
    @property(readonly, strong) NSLayoutXAxisAnchor *leadingAnchor;    //x坐标
    @property(readonly, strong) NSLayoutXAxisAnchor *trailingAnchor;
    @property(readonly, strong) NSLayoutXAxisAnchor *leftAnchor;
    @property(readonly, strong) NSLayoutXAxisAnchor *rightAnchor;
    @property(readonly, strong) NSLayoutYAxisAnchor *topAnchor;    //y坐标
    @property(readonly, strong) NSLayoutYAxisAnchor *bottomAnchor;
    @property(readonly, strong) NSLayoutDimension *widthAnchor;    //宽
    @property(readonly, strong) NSLayoutDimension *heightAnchor;    //高
    @property(readonly, strong) NSLayoutXAxisAnchor *centerXAnchor;
    @property(readonly, strong) NSLayoutYAxisAnchor *centerYAnchor;
    @property(readonly, strong) NSLayoutYAxisAnchor *firstBaselineAnchor;
    @property(readonly, strong) NSLayoutYAxisAnchor *lastBaselineAnchor;
    

    举个简单的例子:
    效果图:


    NSLayoutAnchor.PNG
    _testLayoutAnchor = [[UIView alloc] init];
    _testLayoutAnchor.backgroundColor = [UIColor magentaColor];
    _testLayoutAnchor.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview: _testLayoutAnchor];
        
    [_testLayoutAnchor.topAnchor constraintEqualToAnchor: self.view.topAnchor constant: 84].active = YES;    //距离顶部anchor84
    [_testLayoutAnchor.leadingAnchor constraintEqualToAnchor: self.view.leadingAnchor constant: 20].active = YES;    //距离左边anchor20
    [_testLayoutAnchor.widthAnchor constraintEqualToConstant: 100].active = YES;    //宽100
    [_testLayoutAnchor.heightAnchor constraintEqualToConstant: 100].active = YES;    //高100
    

    4.小结

    iOS约束的实现,或者第三方库约束的实现都是基于NSLayoutConstraint来封装的,万变不离其中,主要熟悉了NSLayoutConstraint,一般的自动化布局也就变的简单。下一章,解析一下,Masonry的源代码。

    相关文章

      网友评论

        本文标题:iOS基础(一) - AutoLayout入门

        本文链接:https://www.haomeiwen.com/subject/whkqmttx.html