Masonry是基于AutoLayout技术的包装,有必不可少先说一下 Masonry 的主干使用

MASConstraintMaker是Masonry框架运营的基本指标之一,我们精晓,梅森ry是基于AutoLayout技术的包装,所以大家来寻觅一下MASConstraintMaker是什么样发挥功效的。

这是 GitHub
上,Masonry
官方对 Masonry 的介绍:

先看一段典型的用法介绍:

Masonry
is a light-weight layout framework which wraps AutoLayout with a nicer
syntax. Masonry has its own layout
DSL
which provides a chainable way of describing your NSLayoutConstraints
which results in layout code that is more concise and readable.
Masonry supports iOS and Mac OS X.

[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.equalTo(superview.mas_top).with.offset(padding.top); //with is an optional semantic filler
    make.left.equalTo(superview.mas_left).with.offset(padding.left);
    make.bottom.equalTo(superview.mas_bottom).with.offset(-padding.bottom);
    make.right.equalTo(superview.mas_right).with.offset(-padding.right);
}];

译文如下:

先是局地 MASConstraintMaker与AutoLayout关系梳理

① 、大家常用的 mas_makeConstraints方法的实现

- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
    self.translatesAutoresizingMaskIntoConstraints = NO;
    MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
    block(constraintMaker);
    return [constraintMaker install];
}

艺术内部创设MASConstraintMaker对象,然后传递到block中,执行完block,调用
[constraintMaker install]来保险约束被添加到视图中去。

二、上面MASConstraintMaker对象的[constraintMaker install]方法

for (MASConstraint *constraint in constraints) {
        constraint.updateExisting = self.updateExisting;
        [constraint install];
    }

能够看出,MASConstraintMaker包罗很多的MASConstraint对象,然后挨家挨户调用MASConstraint对象的install方法。

MASViewConstraint是MASConstraint的子类,成立NSLayoutConstraint添加到视图中去,看一下install方法:

...
MASLayoutConstraint *layoutConstraint
        = [MASLayoutConstraint constraintWithItem:firstLayoutItem
                                        attribute:firstLayoutAttribute
                                        relatedBy:self.layoutRelation
                                           toItem:secondLayoutItem
                                        attribute:secondLayoutAttribute
                                       multiplier:self.layoutMultiplier
                                         constant:self.layoutConstant];

...
...
...
[self.installedView addConstraint:layoutConstraint];

Masonry
是3个轻量级的布局框架,它经过一种祥和的语法封装了自行布局。Masonry
通过链式语法 DSL(Domain-specific
language)

来封装 NSLayoutConstraints,使布局代码尤其人葠简易读。Masonry 扶助 iOS
和 Mac OS X。

其次局部 查看MASConstraintMaker头文件

① 、头文件首先有个别

@property (nonatomic, strong, readonly) MASConstraint *left;
@property (nonatomic, strong, readonly) MASConstraint *top;
@property (nonatomic, strong, readonly) MASConstraint *right;
@property (nonatomic, strong, readonly) MASConstraint *bottom;
@property (nonatomic, strong, readonly) MASConstraint *leading;
@property (nonatomic, strong, readonly) MASConstraint *trailing;
@property (nonatomic, strong, readonly) MASConstraint *width;
@property (nonatomic, strong, readonly) MASConstraint *height;
@property (nonatomic, strong, readonly) MASConstraint *centerX;
@property (nonatomic, strong, readonly) MASConstraint *centerY;
@property (nonatomic, strong, readonly) MASConstraint *baseline;

#if TARGET_OS_IPHONE

@property (nonatomic, strong, readonly) MASConstraint *leftMargin;
@property (nonatomic, strong, readonly) MASConstraint *rightMargin;
@property (nonatomic, strong, readonly) MASConstraint *topMargin;
@property (nonatomic, strong, readonly) MASConstraint *bottomMargin;
@property (nonatomic, strong, readonly) MASConstraint *leadingMargin;
@property (nonatomic, strong, readonly) MASConstraint *trailingMargin;
@property (nonatomic, strong, readonly) MASConstraint *centerXWithinMargins;
@property (nonatomic, strong, readonly) MASConstraint *centerYWithinMargins;

#endif

上边那个是相比较正规的一些品质,在一从头的事例中

make.top.equalTo(superview.mas_top).with.offset(padding.top);

一 、make.top  –>  再次来到七个MASConstraint对象</br>
② 、top.equalTo  –>  再次来到二个block对象,equalTo对应的AutoLayout关系正是NSLayoutRelationEqual,block的接纳参数是id类型,block再次来到值是MASConstraint类型</br>
3、equalTo(superview.mas_top)  –>  调用block,重返MASConstraint类型对象</br>
肆 、with能够忽略,offset类似,那里不详解MASConstraint对象

② 、头文件第贰有的

@property (nonatomic, strong, readonly) MASConstraint *(^attributes)(MASAttribute attrs);

@property (nonatomic, strong, readonly) MASConstraint *edges;

@property (nonatomic, strong, readonly) MASConstraint *size;

@property (nonatomic, strong, readonly) MASConstraint *center;

① 、attributes  –>  重临一个block对象,block的收取参数是MASAttribute类型,再次来到MASCompositeConstraint对象</br>
② 、edges  –>  再次回到一个MASConstraint对象,同时涵盖了上下左右的布局音讯</br>
三 、size  –>  再次来到二个MASConstraint对象,同时富含了宽高的布局消息</br>
④ 、center  –>  重临3个MASConstraint对象,同时涵盖了centerX和centerY消息

在分析 梅森ry 源码此前,有必要先说一下 Masonry 的主导选用,而在说
Masonry 的主干使用此前,大家依然先来看望 storyboard 以及 xib
中是何许进展 AutoLayout 的,笔者截了两张图:

从上海教室大家能够看来,在 storyboard 和 xib
中,大家得以在可视化界面对控件实行 AutoLayout,操作较为简单方便。Masonry
的贯彻原理与这很相似,接下去大家就协同看看哪些利用 Masonry
进行活动布局。

先看一下 Masonry 帮忙什么属性:

/**
 *  以下属性返回一个新的 MASViewConstraint
 */
@property (nonatomic, strong, readonly) MASConstraint *left;      // 左侧
@property (nonatomic, strong, readonly) MASConstraint *top;       // 上侧
@property (nonatomic, strong, readonly) MASConstraint *right;     // 右侧
@property (nonatomic, strong, readonly) MASConstraint *bottom;    // 下侧
@property (nonatomic, strong, readonly) MASConstraint *leading;   // 首部
@property (nonatomic, strong, readonly) MASConstraint *trailing;  // 尾部
@property (nonatomic, strong, readonly) MASConstraint *width;     // 宽
@property (nonatomic, strong, readonly) MASConstraint *height;    // 高
@property (nonatomic, strong, readonly) MASConstraint *centerX;   // 横向居中
@property (nonatomic, strong, readonly) MASConstraint *centerY;   // 纵向居中
@property (nonatomic, strong, readonly) MASConstraint *baseline;  // 文本基线

/**
 *  返回一个 block 对象,block 的接收参数是 MASAttribute 类型,返回一个 MASCompositeConstraint 对象
 */
@property (nonatomic, strong, readonly) MASConstraint *(^attributes)(MASAttribute attrs);

/**
 *  返回一个 MASConstraint 对象,包含上下左右的布局信息
 */
@property (nonatomic, strong, readonly) MASConstraint *edges;

/**
 *  返回一个 MASConstraint 对象,包含宽高的布局信息
 */
@property (nonatomic, strong, readonly) MASConstraint *size;

/**
 *  返回一个 MASConstraint 对象,包含 centerX 和 centerY 信息
 */
@property (nonatomic, strong, readonly) MASConstraint *center;

有了品质之后,怎么着添加约束呢?行使 Masonry
添加约束的函数有四个
,那多少个方法大家在文书 View+MASAdditions
中得以查阅到:

/// 新增约束
- (NSArray *)mas_makeConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block;

/// 更新约束
- (NSArray *)mas_updateConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block;

/// 清除旧约束,只保留新约束
- (NSArray *)mas_remakeConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block;

下边那八个法子中最常用的是
- (NSArray *)mas_makeConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block。即首先个,接下去我们就尝试一下。

举个栗子:

导入 Masonry 框架之后,添加以下代码:

- (void)layoutViews
{
    UIImageView *imageView = [[UIImageView alloc] init];
    [imageView setImage:[UIImage imageNamed:@"123"]];
    [self.view addSubview:imageView];

    [imageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.view).offset(100);
        make.right.equalTo(self.view).offset(-100);
        make.top.equalTo(self.view).offset(250);
        make.bottom.equalTo(self.view).offset(-250);
    }];
}

地点这几句代码便可以对 UIImageView
控件进行封锁,那里还有两点值得一提。第1点:上边这二种方法会完成均等的效果

    /// 第一种
    [imageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.view).offset(100);
        make.right.equalTo(self.view).offset(-100);
        make.top.equalTo(self.view).offset(250);
        make.bottom.equalTo(self.view).offset(-250);
    }];

    /// 第二种
    [imageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.bottom.left.right.equalTo(self.view).insets(UIEdgeInsetsMake(250, 100, 250, 100));
    }];

    /// 第三种
    [imageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.edges.equalTo(self.view).insets(UIEdgeInsetsMake(250, 100, 250, 100));
    }];

三种格局得出的效应图一律:

第二点:非得先把控件添加到视图上,才能对控件进行布局,否则程序会崩。即先
addSubview:,再 mas_makeConstraints:

</br>


上述是对 梅森ry 使用的简要介绍。接下来我们早先分析它的源码

透过对 梅森ry 使用方法的精通,我们得以看来 Masonry
的使用进程可能很简短的

    [imageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.view).offset(100);
        make.right.equalTo(self.view).offset(-100);
        make.top.equalTo(self.view).offset(250);
        make.bottom.equalTo(self.view).offset(-250);
    }];

那大家就从 mas_makeConstraints: 那一个措施开始物色 Masonry
的源码。上文说到,Masonry 中设置约束最常用的情势是

/// 新增约束
- (NSArray *)mas_makeConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block;

而且,Masonry 还提供八个类措施用于更新和重建约束

/// 更新约束
- (NSArray *)mas_updateConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block;

/// 清除旧约束,只保留新约束
- (NSArray *)mas_remakeConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block;

此处大家就以 mas_makeConstraints: 为切入点起首分析 梅森ry
那么些框架。mas_makeConstraints:
这一个法子位于分类View+MASAdditions中,方法的落到实处如下:

/// 新增约束
- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
    /// 我们是手动添加约束,因此将自动转换关闭
    self.translatesAutoresizingMaskIntoConstraints = NO;
    /// 创建 MASConstraintMaker 对象
    MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
    /// 通过 block 进行值的回调
    block(constraintMaker);
    /// 调用 install 方法
    return [constraintMaker install];
}

该格局先去掉 AutoResizing
的自发性转换(即便那个性子没有被正确安装,那么视图的牢笼不会被成功添加),接着起始化三个MASConstraintMaker 对象,传递到 block 中,执行 block,最后调用 install
方法。

先是次点击进入看看那个格局之后,作者有几处疑问。

  • 第贰,MASConstraintMaker 类内部做了哪些操作?
  • 第二,回调 block(constraintMaker)有啥样用?
  • 第三,调用 [constraintMaker install] 方法完结了何等?

</br>

咱俩先来分析一下 MASConstraintMaker 这么些类。MASConstraintMaker 是
Masonry 框架整个 DSL 进程的主宰中央,它控制着一切添加进度,上文大家总计Masonry 支持什么属性时,计算的那一个属性就来源于 MASConstraintMaker
类。大家知晓 Masonry 是基于 AutoLayout
实行的包裹,所以随着大家一道来看下 MASConstraintMaker
是怎么发挥成效的。上面是 MASConstraintMaker 的开头化

///  这里的 MAS_VIEW 是一个宏,#define MAS_VIEW UIView
- (id)initWithView:(MAS_VIEW *)view {
    self = [super init];
    if (!self) return nil;

    self.view = view;
    self.constraints = NSMutableArray.new;

    return self;
}

从上边代码中大家能够清晰的看来,Masonry 在初阶化 MASConstraintMaker
时,将最近的 view 赋给 MASConstraintMaker 类,并先河化3个 constraints
的空可变数组,作为约束数组

除却 MASConstraintMaker 还做了什么样吗?

先赶到 MASConstraintMaker 的头文件 MASConstraintMaker.h
中,上边是一些相比正规的习性

/**
 *    以下属性返回一个新的 MASViewConstraint
 */
@property (nonatomic, strong, readonly) MASConstraint *left;      // 左侧
@property (nonatomic, strong, readonly) MASConstraint *top;       // 上侧
@property (nonatomic, strong, readonly) MASConstraint *right;     // 右侧
@property (nonatomic, strong, readonly) MASConstraint *bottom;    // 下侧
@property (nonatomic, strong, readonly) MASConstraint *leading;   // 首部
@property (nonatomic, strong, readonly) MASConstraint *trailing;  // 尾部
@property (nonatomic, strong, readonly) MASConstraint *width;     // 宽
@property (nonatomic, strong, readonly) MASConstraint *height;    // 高
@property (nonatomic, strong, readonly) MASConstraint *centerX;   // 横向居中
@property (nonatomic, strong, readonly) MASConstraint *centerY;   // 纵向居中
@property (nonatomic, strong, readonly) MASConstraint *baseline;  // 文本基线

其余能够在 MASConstraintMaker 的 MASConstraintMaker.m 中看到另二个属性
@property (nonatomic, strong) NSMutableArray *constraints ,用来存储MASConstraint

@interface MASConstraintMaker () <MASConstraintDelegate>

@property (nonatomic, weak) MAS_VIEW *view;
/// 存储 MASConstraint
@property (nonatomic, strong) NSMutableArray *constraints;

@end

接下去大家透过上面那么些事例来分析上边那些属性:

 [imageView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.bottom.left.right.equalTo(self.view).insets(UIEdgeInsetsMake(250, 100, 250, 100));
    }];
  • block 中第1会履行 make.top
    ,会先调用二个充实约束的通用方法- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute
    ,接着会调用 MASConstraintMaker 中 MASConstraintDelegate 的
    - (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute
    方法。具体代码如下:

/// 重写 getter 方法
- (MASConstraint *)top {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeTop];
}

/// 增加约束的通用方法
- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
    return [self constraint:nil addConstraintWithLayoutAttribute:layoutAttribute];
}

/// 通过 NSLayoutAttribute 添加约束
- (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {

    /// 构造 MASViewAttribute
    MASViewAttribute *viewAttribute = [[MASViewAttribute alloc] initWithView:self.view layoutAttribute:layoutAttribute];

    /// 通过 MASViewAttribute 构造第一个 MASViewConstraint
    MASViewConstraint *newConstraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:viewAttribute];

    /// 如果存在 contraint,则把 constraint 和 newConstraint 组合成 MASCompositeConstraint
    if ([constraint isKindOfClass:MASViewConstraint.class]) {
        //replace with composite constraint
        NSArray *children = @[constraint, newConstraint];
        MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children];
        compositeConstraint.delegate = self;

        /// 替换原来的 constraint 成新的 MASCompositeConstraint
        [self constraint:constraint shouldBeReplacedWithConstraint:compositeConstraint];
        return compositeConstraint;
    }

    /// 不存在则设置 constraint 到 self.constraints
    if (!constraint) {
        /// 设置delegate
        newConstraint.delegate = self;
        /// 将约束添加到self.constraints
        [self.constraints addObject:newConstraint];
    }
    /// 返回刚刚创建的 MASViewConstraint 对象
    return newConstraint;
}

值得一提的是,当调用 make.top 的时候会创立三个只有 firstViewAttribute
的 MASViewConstraint 对象,并且跻身不存在 constraint
的代码部分
,详情见代码块中的注释。

 /// 不存在则设置 constraint 到 self.constraints
    if (!constraint) {
        /// 设置delegate
        newConstraint.delegate = self;
        /// 将约束添加到self.constraints
        [self.constraints addObject:newConstraint];
    }
    /// 返回刚刚创建的 MASViewConstraint 对象
    return newConstraint;

在这些措施的兑现过程中,make.top 的重临值是 MASViewConstraint
对象

  • 当执行到 make.top.bottom 的时候,其实是对 MASViewConstraint 对象
    .bottom 的调用
    ,会走到 MASViewConstraint 中重写的
    - (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute措施,然后最后依旧会调用那个代理方法
    - (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute

- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
    NSAssert(!self.hasLayoutRelation, @"Attributes should be chained before defining the constraint relation");

    return [self.delegate constraint:self addConstraintWithLayoutAttribute:layoutAttribute];
}

/// 通过 NSLayoutAttribute 添加约束
- (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {

    /// 构造 MASViewAttribute
    MASViewAttribute *viewAttribute = [[MASViewAttribute alloc] initWithView:self.view layoutAttribute:layoutAttribute];

    /// 通过 MASViewAttribute 构造第一个 MASViewConstraint
    MASViewConstraint *newConstraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:viewAttribute];

    /// 如果存在 contraint,则把 constraint 和 newConstraint 组合成 MASCompositeConstraint
    if ([constraint isKindOfClass:MASViewConstraint.class]) {
        //replace with composite constraint
        NSArray *children = @[constraint, newConstraint];
        MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children];
        compositeConstraint.delegate = self;

        /// 替换原来的 constraint 成新的 MASCompositeConstraint
        [self constraint:constraint shouldBeReplacedWithConstraint:compositeConstraint];
        return compositeConstraint;
    }

    /// 不存在则设置 constraint 到 self.constraints
    if (!constraint) {
        /// 设置delegate
        newConstraint.delegate = self;
        /// 将约束添加到self.constraints
        [self.constraints addObject:newConstraint];
    }
    /// 返回刚刚创建的 MASViewConstraint 对象
    return newConstraint;
}

和前边的实践进程分化,因为 MASViewConstraint 的 delegate
对象是刚刚设置过的 MASConstraintMaker 对象,并且因为 constraint 不是
nil,所以会进去

/// 如果存在 contraint,则把 constraint 和 newConstraint 组合成 MASCompositeConstraint
    if ([constraint isKindOfClass:MASViewConstraint.class]) {
        //replace with composite constraint
        NSArray *children = @[constraint, newConstraint];
        MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children];
        compositeConstraint.delegate = self;

        /// 替换原来的 constraint 成新的 MASCompositeConstraint
        [self constraint:constraint shouldBeReplacedWithConstraint:compositeConstraint];
        return compositeConstraint;
    }

因此调用 make.top.bottom 重返的是一个 MASCompositeConstraint 对象

  • 当程序执行到 make.top.bottom.left 时,就是对
    MASCompositeConstraint 中 .left 的调用
    ,会走
    MASCompositeConstraint 中的重写方法
    - (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute,接着会调用
    - (MASConstraint *)constraint:(MASConstraint __unused *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute办法,最终依然会调用
    - (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute。代码如下:

- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
    [self constraint:self addConstraintWithLayoutAttribute:layoutAttribute];
    return self;
}

- (MASConstraint *)constraint:(MASConstraint __unused *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
    id<MASConstraintDelegate> strongDelegate = self.delegate;
    MASConstraint *newConstraint = [strongDelegate constraint:self addConstraintWithLayoutAttribute:layoutAttribute];
    newConstraint.delegate = self;
    [self.childConstraints addObject:newConstraint];
    return newConstraint;
}

/// 通过 NSLayoutAttribute 添加约束
- (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {

    /// 构造 MASViewAttribute
    MASViewAttribute *viewAttribute = [[MASViewAttribute alloc] initWithView:self.view layoutAttribute:layoutAttribute];

    /// 通过 MASViewAttribute 构造第一个 MASViewConstraint
    MASViewConstraint *newConstraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:viewAttribute];

    /// 如果存在 contraint,则把 constraint 和 newConstraint 组合成 MASCompositeConstraint
    if ([constraint isKindOfClass:MASViewConstraint.class]) {
        //replace with composite constraint
        NSArray *children = @[constraint, newConstraint];
        MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children];
        compositeConstraint.delegate = self;

        /// 替换原来的 constraint 成新的 MASCompositeConstraint
        [self constraint:constraint shouldBeReplacedWithConstraint:compositeConstraint];
        return compositeConstraint;
    }

    /// 不存在则设置 constraint 到 self.constraints
    if (!constraint) {
        newConstraint.delegate = self;
        [self.constraints addObject:newConstraint];
    }
    return newConstraint;
}

但这次 if ([constraint isKindOfClass:MASViewConstraint.class])
if (!constraint) 都不会进来,只一向回到 MASViewConstraint
对象,然后重返
- (MASConstraint *)constraint:(MASConstraint __unused *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute
方法中安装它的 delegate,并且将指标存入 MASCompositeConstraint 的
childConstraints 中。

  • 今后再有愈来愈多的链式 MASConstraint 的结缘(比如执行到
    make.top.bottom.left.right),也只是 MASCompositeConstraint
    的调用,直接参加 childConstraints 中即可。

  • 至于 equalTo(self.view)
    的调用进程,那里有必不可少说Bellamy下,equalTo(self.view) 在文件
    MASConstraint 中执行 - (MASConstraint * (^)(id))equalTo
    方法,接着调用 MASViewConstraint 中的
    - (MASConstraint * (^)(id, NSLayoutRelation))equalToWithRelation
    方法。代码如下:

/// MASConstraint 是一个抽象类,其中有很多的方法都必须在子类中覆写。Masonry 中有两个 MASConstraint 的子类,分别是 MASViewConstraint 和 MASCompositeConstraint

/// MASConstraint.m
- (MASConstraint * (^)(id))equalTo {
    return ^id(id attribute) {
        return self.equalToWithRelation(attribute, NSLayoutRelationEqual);
    };
}

/// MASViewConstraint.m
- (MASConstraint * (^)(id, NSLayoutRelation))equalToWithRelation {
    return ^id(id attribute, NSLayoutRelation relation) {
        if ([attribute isKindOfClass:NSArray.class]) {
            NSAssert(!self.hasLayoutRelation, @"Redefinition of constraint relation");
            NSMutableArray *children = NSMutableArray.new;

            for (id attr in attribute) {
                MASViewConstraint *viewConstraint = [self copy];
                viewConstraint.layoutRelation = relation;
                viewConstraint.secondViewAttribute = attr;
                [children addObject:viewConstraint];
            }
            MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children];
            compositeConstraint.delegate = self.delegate;
            [self.delegate constraint:self shouldBeReplacedWithConstraint:compositeConstraint];
            return compositeConstraint;
        } else {
            NSAssert(!self.hasLayoutRelation || self.layoutRelation == relation && [attribute isKindOfClass:NSValue.class], @"Redefinition of constraint relation");
            self.layoutRelation = relation;
            self.secondViewAttribute = attribute;
            return self;
        }
    };
}

- (MASConstraint * (^)(id))equalTo 方法提供了参数 attribute 和布局关系
NSLayoutRelationEqual,那四个参数会传送到
- (MASConstraint * (^)(id, NSLayoutRelation))equalToWithRelation
中,设置 constraint 的布局关系和 secondViewAttribute 属性,为
[constraintMaker install] 做准备。

</br>

到那边基本上就把上文的分外例子说完了,通过例子让我们对
MASConstraintMaker 中的一些健康属性有了迟早的刺探,同时也知道了
block(constraintMaker) 这一个方法的功能——在调用
block(constraintMaker) 时,对 constraintMaker 实行布署

MASConstraintMaker 中还有一部分别的属性,大家再一起来看望啊

/**
 *  返回一个 block 对象,block 的接收参数是 MASAttribute 类型,返回一个 MASCompositeConstraint 对象
 */
@property (nonatomic, strong, readonly) MASConstraint *(^attributes)(MASAttribute attrs);

/**
 *    返回一个 MASConstraint 对象,包含上下左右的布局
 */
@property (nonatomic, strong, readonly) MASConstraint *edges;

/**
 *    返回一个 MASConstraint 对象,包含宽高的布局
 */
@property (nonatomic, strong, readonly) MASConstraint *size;

/**
 *    返回一个 MASConstraint 对象,包含 centerX 和 centerY
 */
@property (nonatomic, strong, readonly) MASConstraint *center;

这边只简单的介绍一下上面的多少个属性

  1. attributes:重回一个 block 对象,block 的吸收参数是 MASAttribute
    类型,重回 MASCompositeConstraint 对象
  1. edges:重临贰个 MASConstraint 对象,同时涵盖了内外左右的布局
  2. size:重临二个 MASConstraint 对象,同时涵盖了宽高的布局
  3. center:返回3个 MASConstraint 对象,同时涵盖了 centerX 和centerY

</br>

接下去大家来分析 [constraintMaker install] 方法

我们在- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block
方法的结尾会调用 [constraintMaker install] 方法来添加全部存款和储蓄在
self.constraints 数组中的全体约束。

- (NSArray *)install {
    /// 是否需要删除原来的约束
    if (self.removeExisting) {
        /// 获得所有约束
        NSArray *installedConstraints = [MASViewConstraint installedConstraintsForView:self.view];
        /// 删除所有约束
        for (MASConstraint *constraint in installedConstraints) {
            [constraint uninstall];
        }
    }
    NSArray *constraints = self.constraints.copy;
    for (MASConstraint *constraint in constraints) {
        constraint.updateExisting = self.updateExisting;
        [constraint install];
    }
    /// 去除所有缓存的约束结构体
    [self.constraints removeAllObjects];
    return constraints;
}

那些方法会先判断当前视图的束缚是否必要删除,若是我们事先调用过
- (NSArray *)mas_remakeConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block
那些艺术(它会把 removeExisting 的 BOOL 值设为
YES),那么视图中的原有约束就会被全被删去。接着往下走,程序会遍历
constraints 数组,发送 install 音信。

/// MASViewConstraint.m
- (void)install {
    /// 已经有约束
    if (self.hasBeenInstalled) {
        return;
    }

    /// 支持 active 且已经有约束
    if ([self supportsActiveProperty] && self.layoutConstraint) {
        /// 激活约束
        self.layoutConstraint.active = YES;
        /// 添加约束缓存
        [self.firstViewAttribute.view.mas_installedConstraints addObject:self];
        return;
    }

    /// 获得 firstLayoutItem, firstLayoutAttribute, secondLayoutItem, secondLayoutAttribute
    MAS_VIEW *firstLayoutItem = self.firstViewAttribute.item;
    NSLayoutAttribute firstLayoutAttribute = self.firstViewAttribute.layoutAttribute;
    MAS_VIEW *secondLayoutItem = self.secondViewAttribute.item;
    NSLayoutAttribute secondLayoutAttribute = self.secondViewAttribute.layoutAttribute;

    // alignment attributes must have a secondViewAttribute
    // therefore we assume that is refering to superview
    // eg make.left.equalTo(@10)
    if (!self.firstViewAttribute.isSizeAttribute && !self.secondViewAttribute) {
        secondLayoutItem = self.firstViewAttribute.view.superview;
        secondLayoutAttribute = firstLayoutAttribute;
    }

    /// NSLayoutConstraint 的创建,生成约束,MASLayoutConstraint 其实就是 NSLayoutConstraint 的别名
    MASLayoutConstraint *layoutConstraint
        = [MASLayoutConstraint constraintWithItem:firstLayoutItem
                                        attribute:firstLayoutAttribute
                                        relatedBy:self.layoutRelation
                                           toItem:secondLayoutItem
                                        attribute:secondLayoutAttribute
                                       multiplier:self.layoutMultiplier
                                         constant:self.layoutConstant];

    /// 设置 priority 和 mas_key
    layoutConstraint.priority = self.layoutPriority;
    layoutConstraint.mas_key = self.mas_key;

    /// 如果 secondViewAttribute 有 view 对象
    if (self.secondViewAttribute.view) {
        /// 取得两个 view 的最小公共 view
        MAS_VIEW *closestCommonSuperview = [self.firstViewAttribute.view mas_closestCommonSuperview:self.secondViewAttribute.view];
        NSAssert(closestCommonSuperview,
                 @"couldn't find a common superview for %@ and %@",
                 self.firstViewAttribute.view, self.secondViewAttribute.view);

        /// 设置约束 view 为此 view
        self.installedView = closestCommonSuperview;
    } else if (self.firstViewAttribute.isSizeAttribute) {
        self.installedView = self.firstViewAttribute.view;
    } else {
        self.installedView = self.firstViewAttribute.view.superview;
    }

    /// 已经存在的约束
    MASLayoutConstraint *existingConstraint = nil;
    if (self.updateExisting) { // 需要更新
        existingConstraint = [self layoutConstraintSimilarTo:layoutConstraint];
    }
    if (existingConstraint) { // 如果存在则替换约束
        // just update the constant
        existingConstraint.constant = layoutConstraint.constant;
        self.layoutConstraint = existingConstraint;
    } else {
        /// 其它情况则直接添加约束
        [self.installedView addConstraint:layoutConstraint];
        self.layoutConstraint = layoutConstraint;
        [firstLayoutItem.mas_installedConstraints addObject:self];
    }
}

上面那几个主意是为近年来视图添加约束的最后的艺术,首先那一个方法会先获得即将用于伊始化
NSLayoutConstraint 的子类的多少个属性

    /// MASViewConstraint.m

    /// 获得 firstLayoutItem, firstLayoutAttribute, secondLayoutItem, secondLayoutAttribute
    MAS_VIEW *firstLayoutItem = self.firstViewAttribute.item;
    NSLayoutAttribute firstLayoutAttribute = self.firstViewAttribute.layoutAttribute;
    MAS_VIEW *secondLayoutItem = self.secondViewAttribute.item;
    NSLayoutAttribute secondLayoutAttribute = self.secondViewAttribute.layoutAttribute;

下一场判断当前将要添加的束缚,假诺不是 size 类型并且没有提供
self.secondViewAttribute,会自行将约束添加到 superview 上

    /// MASViewConstraint.m
    if (!self.firstViewAttribute.isSizeAttribute && !self.secondViewAttribute) {
        secondLayoutItem = self.firstViewAttribute.view.superview;
        secondLayoutAttribute = firstLayoutAttribute;
    }

跟着创制 MASLayoutConstraint 对象

/// MASViewConstraint.m
/// NSLayoutConstraint 的创建,生成约束,MASLayoutConstraint 其实就是 NSLayoutConstraint 的别名
    MASLayoutConstraint *layoutConstraint
        = [MASLayoutConstraint constraintWithItem:firstLayoutItem
                                        attribute:firstLayoutAttribute
                                        relatedBy:self.layoutRelation
                                           toItem:secondLayoutItem
                                        attribute:secondLayoutAttribute
                                       multiplier:self.layoutMultiplier
                                         constant:self.layoutConstant];

    /// 设置 priority 和 mas_key
    layoutConstraint.priority = self.layoutPriority;
    layoutConstraint.mas_key = self.mas_key;

创办完约束对象后,大家要物色该约束添加到充足 View
上。下方的代码段便是取得接收该约束对象的视图。尽管是三个视图相对约束,就取得二种的公家父视图。假使加上的是
Width 只怕Height,那么就添加到当前视图上。如若既没有点名相对视图,也不是 Size
类型的自律,那么就将该约束对象添加到当前视图的父视图上。代码落成如下:

/// MASViewConstraint.m
/// 如果 secondViewAttribute 有 view 对象
    if (self.secondViewAttribute.view) {
        /// 取得两个 view 的最小公共 view
        MAS_VIEW *closestCommonSuperview = [self.firstViewAttribute.view mas_closestCommonSuperview:self.secondViewAttribute.view];
        NSAssert(closestCommonSuperview,
                 @"couldn't find a common superview for %@ and %@",
                 self.firstViewAttribute.view, self.secondViewAttribute.view);

        /// 设置约束 view 为此 view
        self.installedView = closestCommonSuperview;
    } else if (self.firstViewAttribute.isSizeAttribute) {
        self.installedView = self.firstViewAttribute.view;
    } else {
        self.installedView = self.firstViewAttribute.view.superview;
    }

加约束时我们要认清是不是供给对约束举行更新,尽管急需,就替换约束,假使不要求就一向助长约束即可。添加成功后我们将经过
mas_installedConstraints 属性记录一下此次添加的束缚。

   /// 已经存在的约束
    MASLayoutConstraint *existingConstraint = nil;
    if (self.updateExisting) { // 需要更新
        existingConstraint = [self layoutConstraintSimilarTo:layoutConstraint];
    }
    if (existingConstraint) { // 如果存在则替换约束
        // just update the constant
        existingConstraint.constant = layoutConstraint.constant;
        self.layoutConstraint = existingConstraint;
    } else {
        /// 其它情况则直接添加约束
        [self.installedView addConstraint:layoutConstraint];
        self.layoutConstraint = layoutConstraint;
        [firstLayoutItem.mas_installedConstraints addObject:self];
    }

</br>

到此停止,对
Masonry
源码的简易介绍已接近尾声了。。。Masonry
的代码流程简单来说正是提必要大家二个 MASConstraintMaker,然后大家依照Masonry 提供的语法,添加约束。最终 Masonry
解析约束,将真正的约束关系添加到相应的视图上。