Masonry库 内容


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尺寸,并且不能修改。

   UIView *subView = [UIView new];
    [self.view addSubview:subView];
    [subView mas_makeConstraints:^(MASConstraintMaker *make) {;
    subView.backgroundColor = [UIColor redColor];
    UIView *subView1 = [UIView new];
    [self.view addSubview:subView1];
    [subView1 mas_makeConstraints:^(MASConstraintMaker *make) {;
    subView1.backgroundColor = [UIColor yellowColor];
// 约束的不等式关系
typedef NS_ENUM(NSInteger, NSLayoutRelation) {
    NSLayoutRelationLessThanOrEqual = -1,
    NSLayoutRelationEqual = 0,
    NSLayoutRelationGreaterThanOrEqual = 1,
NSLayoutAttributeLeading: 在习惯由左向右看的地区,相当于NSLayoutAttributeLeft;在习惯从右至左看的地区,相当于NSLayoutAttributeRight;
NSLayoutAttributeTrailing: 在习惯由左向右看的地区,相当于NSLayoutAttributeRight;在习惯从右至左看的地区,相当于NSLayoutAttributeLeft;
// ```下一次我们的label是可以使用NSLayoutAttributeLastBaseline 或者NSLayoutAttributeFirstBaseline 来进行设置约束```
typedef NS_ENUM(NSInteger, NSLayoutAttribute) {
    NSLayoutAttributeLeft = 1,// 左边
    NSLayoutAttributeRight, // 右
    NSLayoutAttributeLeading, // 
    NSLayoutAttributeLastBaseline, // 文本的下标标
    NSLayoutAttributeBaseline NS_SWIFT_UNAVAILABLE("Use 'lastBaseline' instead") = NSLayoutAttributeLastBaseline,  // 文本的最后一行的距离
    NSLayoutAttributeBaseline = NSLayoutAttributeLastBaseline, 
    NSLayoutAttributeFirstBaseline API_AVAILABLE(macos(10.11), ios(8.0)), //文本的第一行的距离

#if TARGET_OS_IPHONE // margin 默认的margin内容
    NSLayoutAttributeLeftMargin API_AVAILABLE(ios(8.0)),
    NSLayoutAttributeRightMargin API_AVAILABLE(ios(8.0)),
    NSLayoutAttributeTopMargin API_AVAILABLE(ios(8.0)),
    NSLayoutAttributeBottomMargin API_AVAILABLE(ios(8.0)),
    NSLayoutAttributeLeadingMargin API_AVAILABLE(ios(8.0)),
    NSLayoutAttributeTrailingMargin API_AVAILABLE(ios(8.0)),
    NSLayoutAttributeCenterXWithinMargins API_AVAILABLE(ios(8.0)),
    NSLayoutAttributeCenterYWithinMargins API_AVAILABLE(ios(8.0)),
    NSLayoutAttributeNotAnAttribute = 0 // 有关属性没有
typedef float UILayoutPriority NS_TYPED_EXTENSIBLE_ENUM;
static const UILayoutPriority UILayoutPriorityRequired API_AVAILABLE(ios(6.0)) = 1000; // A required constraint.  Do not exceed this.
static const UILayoutPriority UILayoutPriorityDefaultHigh API_AVAILABLE(ios(6.0)) = 750; // This is the priority level with which a button resists compressing its content.
static const UILayoutPriority UILayoutPriorityDragThatCanResizeScene API_AVAILABLE(macCatalyst(13.0)) = 510; // This is the appropriate priority level for a drag that may end up resizing the window's scene.
static const UILayoutPriority UILayoutPrioritySceneSizeStayPut API_AVAILABLE(macCatalyst(13.0)) = 500; // This is the priority level at which the window's scene prefers to stay the same size.  It's generally not appropriate to make a constraint at exactly this priority. You want to be higher or lower.
static const UILayoutPriority UILayoutPriorityDragThatCannotResizeScene API_AVAILABLE(macCatalyst(13.0)) = 490; // This is the priority level at which a split view divider, say, is dragged.  It won't resize the window's scene.
static const UILayoutPriority UILayoutPriorityDefaultLow API_AVAILABLE(ios(6.0)) = 250; // This is the priority level at which a button hugs its contents horizontally.
static const UILayoutPriority UILayoutPriorityFittingSizeLevel API_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.

typedef float NSLayoutPriority NS_TYPED_EXTENSIBLE_ENUM;
#endif /* !TARGET_OS_IPHONE */

NSLayoutConstraint 类提供的方法:

+ (NSArray<NSLayoutConstraint *> *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(nullable NSDictionary<NSString *, id> *)metrics views:(NSDictionary<NSString *, id> *)views API_AVAILABLE(macos(10.7), ios(6.0), tvos(9.0)); 创建约束, 这个是使用VF的方式
/* Create an array of constraints using an ASCII-art-like visual format string.  The values of the `metrics` dictionary should be NSNumber (or some other type that responds to -doubleValue and returns a double).
+ (NSArray<NSLayoutConstraint *> *)constraintsWithVisualFormat:(NSString *)format options:(NSLayoutFormatOptions)opts metrics:(nullable NSDictionary<NSString *, id> *)metrics views:(NSDictionary<NSString *, id> *)views API_AVAILABLE(macos(10.7), ios(6.0), tvos(9.0));

/* This macro is a helper for making view dictionaries for +constraintsWithVisualFormat:options:metrics:views:.
 NSDictionaryOfVariableBindings(v1, v2, v3) is equivalent to [NSDictionary dictionaryWithObjectsAndKeys:v1, @"v1", v2, @"v2", v3, @"v3", nil];
#define NSDictionaryOfVariableBindings(...) _NSDictionaryOfVariableBindings(@"" # __VA_ARGS__, __VA_ARGS__, nil)
NSLAYOUTCONSTRAINT_EXTERN NSDictionary<NSString *, id> *_NSDictionaryOfVariableBindings(NSString *commaSeparatedKeysString, __nullable id firstValue, ...) API_AVAILABLE(macos(10.7), ios(6.0)); // not for direct use

```一般上面的两个方法是结合起来使员工的的 ,binds的返回值作为第一个方法的最后一个参数```

// 最常用的一个设置约束的算法, 这个只是产生一个约束
+ (instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(nullable id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c API_AVAILABLE(macos(10.7), ios(6.0), tvos(9.0));

@property UILayoutPriority priority; // 约束的优先级属性
@property NSLayoutPriority priority;

/* When a view is archived, it archives some but not all constraints in its -constraints array.  The value of shouldBeArchived informs the view if a particular constraint should be archived by the view.
 If a constraint is created at runtime in response to the state of the object, it isn't appropriate to archive the constraint - rather you archive the state that gives rise to the constraint.  Since the majority of constraints that should be archived are created in Interface Builder (which is smart enough to set this prop to YES), the default value for this property is NO.
// 有可能view被归档,但是这个contstraints是否需要归档, 而xib的约束是自能归档的
@property BOOL shouldBeArchived;

/* accessors
 firstItem.firstAttribute {==,<=,>=} secondItem.secondAttribute * multiplier + constant
 Access to these properties is not recommended. Use the `firstAnchor` and `secondAnchor` properties instead.
通过第一个是关系的左边约束, 第二个是关系的右边参数
@property (nullable, readonly, assign) id firstItem;
@property (nullable, readonly, assign) id secondItem;
@property (readonly) NSLayoutAttribute firstAttribute;
@property (readonly) NSLayoutAttribute secondAttribute;

/* accessors
 firstAnchor{==,<=,>=} secondAnchor * multiplier + constant
@property (readonly, copy) NSLayoutAnchor *firstAnchor API_AVAILABLE(macos(10.12), ios(10.0));
@property (readonly, copy, nullable) NSLayoutAnchor *secondAnchor API_AVAILABLE(macos(10.12), ios(10.0));

@property (readonly) NSLayoutRelation relation; // 关系枚举变量值
@property (readonly) CGFloat multiplier; // 倍率, 多少倍率

/* Unlike the other properties, the constant may be modified after constraint creation.  Setting the constant on an existing constraint performs much better than removing the constraint and adding a new one that's just like the old but for having a new constant.
@property CGFloat constant; // 有关的常量值 , 这个可以使之新的值

/* The receiver may be activated or deactivated by manipulating this property.  Only active constraints affect the calculated layout.  Attempting to activate a constraint whose items have no common ancestor will cause an exception to be thrown.  Defaults to NO for newly created constraints. */
@property (getter=isActive) BOOL active API_AVAILABLE(macos(10.10), ios(8.0));

/* Convenience method that activates each constraint in the contained array, in the same manner as setting active=YES. This is often more efficient than activating each constraint individually. */
// 设置约束有效
+ (void)activateConstraints:(NSArray<NSLayoutConstraint *> *)constraints API_AVAILABLE(macos(10.10), ios(8.0));

/* Convenience method that deactivates each constraint in the contained array, in the same manner as setting active=NO. This is often more efficient than deactivating each constraint individually. */
// 设置约束失效
+ (void)deactivateConstraints:(NSArray<NSLayoutConstraint *> *)constraints API_AVAILABLE(macos(10.10), ios(8.0));

/// 一个约束的唯一标识, 可以在调试的时候设置identifier, 有利于调试
@property (nullable, copy) NSString *identifier API_AVAILABLE(macos(10.7), ios(7.0)); 

 UILayoutSupport protocol is implemented by layout guide objects
 returned by UIViewController properties topLayoutGuide and bottomLayoutGuide.
 These guide objects may be used as layout items in the NSLayoutConstraint
 factory methods.
@class NSLayoutYAxisAnchor, NSLayoutDimension;、
// 这个协议,不知道有什么作用、?

@protocol UILayoutSupport <NSObject>
@property(nonatomic,readonly) CGFloat length;  // As a courtesy when not using auto layout, this value is safe to refer to in -viewDidLayoutSubviews, or in -layoutSubviews after calling super

// 锚点, 只读的内容
/* Constraint creation conveniences. See NSLayoutAnchor.h for details.
@property(readonly, strong) NSLayoutYAxisAnchor *topAnchor API_AVAILABLE(ios(9.0));
@property(readonly, strong) NSLayoutYAxisAnchor *bottomAnchor API_AVAILABLE(ios(9.0));
@property(readonly, strong) NSLayoutDimension *heightAnchor API_AVAILABLE(ios(9.0));
MASUtilities.h 这个文件: 定义了一个mac和ios的统一的声明 , MASAttachKeys 绑定的方法 , hash值的算法, _MASBoxValue 这个用来获取对应的值

[escape 的介绍](
[swift 和OC中的escape](

简写的分类 ,下一次我们也可以这样去写,不过一般有前缀

// 常见的拼接代码
#define MAS_ATTR_FORWARD(attr)  \
- (MASViewAttribute *)attr {    \
    return [self mas_##attr];   \



![(2)constraints 中的另一个设置约束的系统方式](

 有了山上面的基本基础内容, 我们可以看一下源码了; 

MASLayoutConstraint  这个类就是NSLayoutContraint类, 这个增加了一个key用来调试,其实现在系统就有了Identifier的; 
MASConstraint 设置约束最为基本的类; 包括基本的元素:方位、不等式关系、偏差距离 
MASCompositeConstraint:  MASConstraint  这个是上面元素的组合方式,一般for循环多个
MASViewConstraint:MASConstraint  就是设置一个约束的最基本的单元: 又有了约束的所有的基本变量
>```firstViewAttribute(第一个属性)、secondViewAttribute(第二个属性)、installedView(安装的View)、 layoutConstraint(布局约束)、layoutRelation(等式关系)、layoutPriority(权限优先级) layoutConstant(约束设置的敞亮) hasLayoutRelation(是否已经有了不等式关系)mas_key(调试的key)  useAnimator```

MASViewAttribute : view + layout(方位) 描述一个约束的一边,不等式一边的内容
MASConstraint+Private : 这个是声明了一些方法给库里面的其他文件调用; 
MASConstraintMaker 约束工厂: NSObject ,最为主要的调用, 组织对应的内容, 然后让MASViewConstraint 进行设置自己的约束内容

NSLayoutConstraint+MASDebugAdditions 测试的分类
View+MASShorthandAdditions   // 便利使用方法
NSArray+MASShorthandAdditions // 扩展的遍历使用方法
   uiviewController 里面的一些简单使用
MASConstraintMaker 关键方法, 添加单个约束以及组合约束

MASViewConstraint 类的安装基本方法
- (void)install {
    if (self.hasBeenInstalled) {
    if ([self supportsActiveProperty] && self.layoutConstraint) { = YES;
        [self.firstViewAttribute.view.mas_installedConstraints addObject:self];
    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;
// 获取不等式两边的内容
    MASLayoutConstraint *layoutConstraint
        = [MASLayoutConstraint constraintWithItem:firstLayoutItem
    layoutConstraint.priority = self.layoutPriority;
    layoutConstraint.mas_key = self.mas_key;   
// 设置约束 

    if (self.secondViewAttribute.view) { 
        MAS_VIEW *closestCommonSuperview = [self.firstViewAttribute.view mas_closestCommonSuperview:self.secondViewAttribute.view];
                 @"couldn't find a common superview for %@ and %@",
                 self.firstViewAttribute.view, self.secondViewAttribute.view);
        self.installedView = closestCommonSuperview;
    } else if (self.firstViewAttribute.isSizeAttribute) {
        self.installedView = self.firstViewAttribute.view;
    } else {
        self.installedView = self.firstViewAttribute.view.superview;
// 获取安装的view, 这个安装的View,两个View的公共最近的View

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

// 查找对应的类似的方法
- (MASLayoutConstraint *)layoutConstraintSimilarTo:(MASLayoutConstraint *)layoutConstraint {
    // check if any constraints are the same apart from the only mutable property constant

    // go through constraints in reverse as we do not want to match auto-resizing or interface builder constraints
    // and they are likely to be added first.
    for (NSLayoutConstraint *existingConstraint in self.installedView.constraints.reverseObjectEnumerator) {
        if (![existingConstraint isKindOfClass:MASLayoutConstraint.class]) continue;
        if (existingConstraint.firstItem != layoutConstraint.firstItem) continue;
        if (existingConstraint.secondItem != layoutConstraint.secondItem) continue;
        if (existingConstraint.firstAttribute != layoutConstraint.firstAttribute) continue;
        if (existingConstraint.secondAttribute != layoutConstraint.secondAttribute) continue;
        if (existingConstraint.relation != layoutConstraint.relation) continue;
        if (existingConstraint.multiplier != layoutConstraint.multiplier) continue;
        if (existingConstraint.priority != layoutConstraint.priority) continue;

        return (id)existingConstraint;
    return nil;

// 查找两个View的最近公共父View , 这个还是使用了这个View while循环遍历,相对for好一点
- (instancetype)mas_closestCommonSuperview:(MAS_VIEW *)view {
    MAS_VIEW *closestCommonSuperview = nil;

    MAS_VIEW *secondViewSuperview = view;
    while (!closestCommonSuperview && secondViewSuperview) {
        MAS_VIEW *firstViewSuperview = self;
        while (!closestCommonSuperview && firstViewSuperview) {
            if (secondViewSuperview == firstViewSuperview) {
                closestCommonSuperview = secondViewSuperview;
            firstViewSuperview = firstViewSuperview.superview;
        secondViewSuperview = secondViewSuperview.superview;
    return closestCommonSuperview;

延伸 : 看一下工厂的设计模块式;
简单工厂: 简单工厂模式
工厂方法: 简单工厂方法