iOS基礎(chǔ)(一) - AutoLayout入門

前言

蘋果在iOS6就出了自動化布局(NSLayoutConstraint),很多第三方庫就是基于原生的類的封裝,比如:Masonry等。在iOS9的時候,加入了NSLayoutAnchor這個類,大大簡化了原生的自動化布局。下面就從NSLayoutConstrint這個類說起。

1.NSLayoutConstraint

首先,我們需要了解到一個基本常識,就是多少約束可以最終確定一個物體的位置。我們繪畫的時候會從大概一個點(diǎn)開始畫,然后以這個點(diǎn)作為參照,逐步繪制整個畫面。同理,確定一個物體,也先要確定一個參考點(diǎn),這里稱為初始點(diǎn),學(xué)過數(shù)學(xué)的坐標(biāo)系的同學(xué)都清楚,在平面坐標(biāo)系,確定一個點(diǎn)需要橫坐標(biāo)和縱坐標(biāo),而作為一個添加在父控件的子控件,初始點(diǎn)的橫坐標(biāo)就是距離父控件的左邊間距或者右邊間距,縱坐標(biāo)就是距離父控件的頂部間距或者底部間距。初始點(diǎn)確定了,我們開始繪制圖形。由于繪制區(qū)域都是矩形,所以,在初始點(diǎn)確定之后,只需要寬和高就能繪制出一個完整的矩形。所以,至少需要四個約束,才能最終確定一個物體,兩個約束確定一個初始點(diǎn),兩個約束確定寬和高。

廢話不多說,開始進(jìn)入正題:

(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的區(qū)別:
NSLayoutAttributeLeft指的是控件的左邊,具體來說是控件的最左邊;NSLayoutAttributeLeftMargin也是指控件的左邊,但是不是最左邊,具體距離最左邊有多大的Margin和控件的layoutMargins有關(guān)。
蘋果官方的描述:

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

注:默認(rèn)是{8,8,8,8},但是如果是viewController的root view則top和bottom的margins為0,左右margins可能是16或者20,這取決于當(dāng)前的view尺寸,并且不能修改。

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

該選項是用于兩個約束的比較,例如:view2的左邊距離view1的右邊20個點(diǎn)。(view2.left = view1.right * 1 + 20)

(3)UILayoutPriority優(yōu)先級
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.

優(yōu)先級只有在兩個約束有沖突的時候才起作用,優(yōu)先級高的會覆蓋優(yōu)先級低的,最高的優(yōu)先級為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];
    
//添加約束方式一
//調(diào)用父控件添加約束的函數(shù),添加子控件約束
//控件約束對象必須是擁有同一父控件的子控件或者是父控件
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]];

//添加約束方式二
//調(diào)用NSLayoutConstraint的類方法使約束生效(iOS8以后)
[NSLayoutConstraint activateConstraints: @[leftViewLeftConstraint, leftViewTopConstraint, leftViewWidth, leftViewHeight, rightViewLeftConstraint, rightViewTopConstraint, rightViewWith, rightViewHeight]];

//添加約束方式三
//直接將約束的active設(shè)置為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];

//首先,設(shè)置leftView的約束
[NSLayoutConstraint constraintWithItem: leftView attribute: NSLayoutAttributeTop relatedBy: NSLayoutRelationEqual toItem: self.view attribute: NSLayoutAttributeTop multiplier: 1.0 constant: 84].active = YES;    //leftView頂部距離父控件84個點(diǎn)
[NSLayoutConstraint constraintWithItem: leftView attribute: NSLayoutAttributeLeft relatedBy: NSLayoutRelationEqual toItem: self.view attribute: NSLayoutAttributeLeft multiplier: 1.0 constant: 20].active = YES;    //leftView左邊距離父控件20個點(diǎn)
[NSLayoutConstraint constraintWithItem: leftView attribute: NSLayoutAttributeHeight relatedBy: NSLayoutRelationEqual toItem: nil attribute: NSLayoutAttributeNotAnAttribute multiplier: 1.0 constant: 200].active = YES;    //leftView的height=200,這里寬在后面設(shè)置

//其次,設(shè)置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個點(diǎn)

//最后,二等分的魔法就要開始了
//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個點(diǎn)

//可以把leftView和rightView看作一個整體,那么這個整體就是left=super.left+20,right=super.right-20,top=super.top+20,height=200,四個約束可以確定一個view的位置
//這時候來看內(nèi)部的約束,首先,leftView.width=rightView.width,leftView.right=rightView.left-20,所以,leftView和rightView等分

?? 三:約束動畫(這里涉及到約束優(yōu)先級)
效果動圖:


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];
    
//設(shè)置三個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),優(yōu)先級設(shè)置比默認(rèn)的低,這樣在和grayView.left=purpleView.right+20(@1000)約束有沖突的時候,系統(tǒng)會忽略優(yōu)先級低的約束,所以,剛開始顯示是紅紫灰
_animateConstraint = [NSLayoutConstraint constraintWithItem: _grayView attribute: NSLayoutAttributeLeft relatedBy: NSLayoutRelationEqual toItem: _redView attribute: NSLayoutAttributeRight multiplier: 1.0 constant: 20];
_animateConstraint.priority = UILayoutPriorityDefaultLow;
[self.view addConstraint: _animateConstraint];

//觸發(fā)動畫
//將中間紫色的view移除
//標(biāo)記頁面刷新,并立刻刷新
//這時候由于第二個view被移除了,所以優(yōu)先級低的約束就起作用了
[_purpleView removeFromSuperview];
[UIView animateWithDuration: 0.2 animations:^{
    [self.view setNeedsLayout];
    [self.view layoutIfNeeded];
}];

2.VFL

VFL其實也是對NSLayoutConstraint的封裝,更為具像化,目的就是為了簡化自動化布局。在我看來,入門有點(diǎn)復(fù)雜,入門后就比較簡單。呵呵噠,具體見仁見智。

(1)VFL語法:
表達(dá)式 功能
H: 水平方向
V: 垂直方向
[view] 視圖
l 父控件邊界
>=,==,<= 約束不等式
- 間隙,連接視圖和約束,視圖和視圖
@value 優(yōu)先級
/**
 *  VFL創(chuàng)建約束
 *
 *
 *  @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 返回包含一系列約束的數(shù)組
 *
 */

+ (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),    //相當(dāng)于NSLayoutFormatAlignAllLeft
    NSLayoutFormatAlignAllTrailing = (1 << NSLayoutAttributeTrailing),    //相當(dāng)于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];

?? 三:約束動畫(這里涉及到約束優(yōu)先級)

_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];

//觸發(fā)動畫
[_purpleView removeFromSuperview];
[UIView animateWithDuration: 0.2 animations:^{
    [self.view setNeedsLayout];
    [self.view layoutIfNeeded];
}];

另外添加一個?? ,就是兩個view不等高的情況:
效果圖:


例子四.PNG
//這里利用優(yōu)先級不同來解決問題
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)]";    //先設(shè)置優(yōu)先級低于默認(rèn)優(yōu)先級
NSString *vConstraint2 = @"V:[rightView(120)]";    //默認(rèn)優(yōu)先級1000,會覆蓋前面優(yōu)先級低的約束
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坐標(biāo),y坐標(biāo)和寬高。

NSLayoutAnchor屬性
/* Constraint creation conveniences. See NSLayoutAnchor.h for details.
 */
@property(readonly, strong) NSLayoutXAxisAnchor *leadingAnchor;    //x坐標(biāo)
@property(readonly, strong) NSLayoutXAxisAnchor *trailingAnchor;
@property(readonly, strong) NSLayoutXAxisAnchor *leftAnchor;
@property(readonly, strong) NSLayoutXAxisAnchor *rightAnchor;
@property(readonly, strong) NSLayoutYAxisAnchor *topAnchor;    //y坐標(biāo)
@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.小結(jié)

iOS約束的實現(xiàn),或者第三方庫約束的實現(xiàn)都是基于NSLayoutConstraint來封裝的,萬變不離其中,主要熟悉了NSLayoutConstraint,一般的自動化布局也就變的簡單。下一章,解析一下,Masonry的源代碼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,908評論 2 372

推薦閱讀更多精彩內(nèi)容