Masonry代码解读

作者: mkb2 | 来源:发表于2019-01-14 21:25 被阅读89次

    一.前言

    Masonry是非常有名的布局框架,今天我们就分析它的具体实现。通读了一边源码,写的非常的好,有很多值得我们学习的地方。

    二.前期准备

    Masonry之所以非常让人着迷,得益于简单的api和链式编程,提高约束代码的可读性。

    例如:

    [greenView mas_makeConstraints:^(MASConstraintMaker *make) {
            make.width.mas_greaterThanOrEqualTo(200);
            make.width.mas_lessThanOrEqualTo(340);
            make.height.mas_equalTo(40);
            make.left.mas_greaterThanOrEqualTo(view1);
            make.top.mas_equalTo(120);
        }];
    

    要阅读Masonry源码,首先要了解链式编程组合模式,其中组合模式格外重要,因为Masonry中使用了该设计模式。

    三.整体结构图 & 各类提供的作用

    Masonry架构图
    • 1.View+MASAdditions.h
      UIView(如果是macOS,则为NSView)提供创建make的方法,方便实现布局。并且提供当前viewmas_xxx属性

      // 获取两个view最近superview
      - (instancetype)mas_closestCommonSuperview:(MAS_VIEW *)view;
      - (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;
      
    • 2.MASConstraintMaker
      提供单一的约束属性和组合约束属性,提供install方法。

      // 单一约束属性,get方法,都是创建一个Constraint
      @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;
      
      // 组合约束属性,用于一次性创建多个Constraint
      @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;
      
      // 将约束设置到view上
      - (NSArray *)install;
      
    • 3.MASConstraint
      特别注意:是一个抽象类,声明方法和属性,不实现具体的方法,都要子类实现!!!
      并且声明了一下方法,使链式编程变为可能。

      // 声明get方法,用于创建MASConstraint,然后添加到make的数组中。通过Constraint的addConstraintWithLayoutAttribute来添加,具体逻辑由子类实现。
      - (MASConstraint *)left;
      - (MASConstraint *)top;
      - (MASConstraint *)right;
      - (MASConstraint *)bottom;
      - (MASConstraint *)leading;
      - (MASConstraint *)trailing;
      - (MASConstraint *)width;
      - (MASConstraint *)height;
      - (MASConstraint *)centerX;
      - (MASConstraint *)centerY;
      - (MASConstraint *)baseline;
      
      // 为constraint添加属性或equal关系,然后返回self(MASConstraint)
      - (MASConstraint * (^)(MASLayoutPriority priority))priority;
      - (MASConstraint * (^)(void))priorityLow;
      - (MASConstraint * (^)(void))priorityMedium;
      - (MASConstraint * (^)(void))priorityHigh;
      - (MASConstraint * (^)(id attr))equalTo;
      
      // 安装约束到targetView上
      - (void)install;
      - (void)uninstall;
      
    • 4.MASViewConstraint
      继承于MASConstraint,实现抽象类的方法。是对约束所需要所有属性的封装。

    在组合模式中,属于叶子节点!!!不可以添加子节点。Masonry中如果想让叶子节点变为树枝节点,会将两个叶子节点放到一个数组中,然后创建一个树枝节点,然后用树枝节点替换叶子节点的位置。

    // 布局公式:view1.attr1 = view2.attr2 * multiplier + constant 
    
    // view1的各个属性参数
    @property (nonatomic, strong, readonly) MASViewAttribute *firstViewAttribute;
    // view2的各个属性参数,secondViewAttribute可以是NSValue,UIView,MASViewAttribute,提供了较多的方式,后续会分析
    @property (nonatomic, strong, readonly) MASViewAttribute *secondViewAttribute;
    // 某个view已安装的约束
    + (NSArray *)installedConstraintsForView:(MAS_VIEW *)view;
    
     // .m文件实现方法
    - (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute;
    // 非常重要的方法
    - (void)install;
    
    • 5.MASCompositeConstraint
      继承于MASConstraint,实现抽象类的方法。内部维护一个数组,全部都是MASViewConstraint对象。

      在组合模式中,是树枝节点,内部维护一个数组,可以添加叶子节点。

      // .h 文件
      - (id)initWithChildren:(NSArray *)children;
      // .m 文件中实现了抽象类的方法
      基本上就是for循环变量MASViewConstraint,然后执行对应名称的方法而已。唯一特别的就是它可以add叶子节点!!!
      
      #pragma mark - MASConstraintDelegate   稍后分析
      
      - (void)constraint:(MASConstraint *)constraint shouldBeReplacedWithConstraint:(MASConstraint *)replacementConstraint;
      - (MASConstraint *)constraint:(MASConstraint __unused *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute;
      
    • 6.MASConstraint+Private.h
      声明了MASConstraintDelegate代理方法。
      MASCompositeConstraintMASConstraintMaker实现的。

      @protocol MASConstraintDelegate <NSObject>
      
      //  当组合模式中,要将叶子节点替换为树枝节点,使用此方法
      - (void)constraint:(MASConstraint *)constraint shouldBeReplacedWithConstraint:(MASConstraint *)replacementConstraint;
      
      // 将叶子节点添加到组合模式中
      - (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute;
      
      @end
      
    关系图&委托关系

    四.Masonsy 如何工作的

    下面通过代码来看看Masonry是如何运作的,代码如下:

    [view1 mas_makeConstraints:^(MASConstraintMaker *make) {
            make.top.left.bottom.mas_equalTo(20);
            make.width.mas_equalTo(40)�;
     }];
    
    4.1创建make对象,执行block
    - (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
        // a.关闭转换AutoresizingMask至Constraints的属性
        self.translatesAutoresizingMaskIntoConstraints = NO;
        // b.创建make,用weak保存self(设置约束的view)
        MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
        // c.执行block,make.top.left.bottom.mas_equalTo(20); && make.width.mas_equalTo(40)�;
        block(constraintMaker);
        // d.执行install操作
        return [constraintMaker install];
    }
    
    4.2 block(constraintMaker);

    这里执行make.top语句,即:

    // make.x 直接返回MASConstraint对象
    - (MASConstraint *)top {
        return [self addConstraintWithLayoutAttribute:NSLayoutAttributeTop];
    }
    
    - (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
        return [self constraint:nil addConstraintWithLayoutAttribute:layoutAttribute];
    }
    
    #pragma mark - MASConstraintDelegate 实现的代理方法
    
    - (void)constraint:(MASConstraint *)constraint shouldBeReplacedWithConstraint:(MASConstraint *)replacementConstraint {
       // 如果将viewConstraint替换为compositionConstaint,调用此方法
        NSUInteger index = [self.constraints indexOfObject:constraint];
        NSAssert(index != NSNotFound, @"Could not find constraint %@", constraint);
        [self.constraints replaceObjectAtIndex:index withObject:replacementConstraint];
    }
    
    // 该方法是将树枝节点或者是叶子节点直接存放到make.constraints数组中
    - (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
        // 如果是make.x 的时候,constraint = nil,就是创建一个MASViewConstraint
        MASViewAttribute *viewAttribute = [[MASViewAttribute alloc] initWithView:self.view layoutAttribute:layoutAttribute];
        MASViewConstraint *newConstraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:viewAttribute];
        if ([constraint isKindOfClass:MASViewConstraint.class]) {
            // 将MASViewConstraint 变成MASCompositeConstraint使用调用。
            // make.top.left的时候会执行到这里 ,make.top.left.bottom也会执行到这里。实际上就是MASCompositeConstraint存放了三个MASViewConstraint。
            // MASCompositeConstraint放置在make.constraints数组中。典型的组合模式
            NSArray *children = @[constraint, newConstraint];
            MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children];
            compositeConstraint.delegate = self;
            [self constraint:constraint shouldBeReplacedWithConstraint:compositeConstraint];
            return compositeConstraint;
        }
        // 当前make.top会执行这里newConstraint = topConstraint,将topConstraint.delegate = self(make)
        if (!constraint) {
            newConstraint.delegate = self;
            [self.constraints addObject:newConstraint];
        }
        return newConstraint;
    }
    

    这里执行make.top.left语句,刚才通过make.top返回了MASViewConstraint对象,现在看看MASViewConstraint.left的函数实现

    // 重写父类方法
    #pragma mark - attribute chaining
    
    - (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
        NSAssert(!self.hasLayoutRelation, @"Attributes should be chained before defining the constraint relation");
        // 此时self = newConstraint,layoutAttribute = left,带着constraint:self参数调用了代理方法,此时self.delegate = make
        return [self.delegate constraint:self addConstraintWithLayoutAttribute:layoutAttribute];
    }
    

    此时会调用make的方法,返回CompositionConstraint对象

    // make.m 文件
    - (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
        MASViewAttribute *viewAttribute = [[MASViewAttribute alloc] initWithView:self.view layoutAttribute:layoutAttribute];
        MASViewConstraint *newConstraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:viewAttribute];
        // constraint = topConstraint
        if ([constraint isKindOfClass:MASViewConstraint.class]) {
            //replace with composite constraint
            NSArray *children = @[constraint, newConstraint];
            MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children];
            compositeConstraint.delegate = self;
            [self constraint:constraint shouldBeReplacedWithConstraint:compositeConstraint];
            return compositeConstraint;
        }
        //下面代码不会执行
        if (!constraint) {
            newConstraint.delegate = self;
            [self.constraints addObject:newConstraint];
        }
        return newConstraint;
    }
    

    执行make.top.left.bottom代码
    会执行MASCompositionConstraint.bottom方法。
    该代码的含义,就是创建了bottomViewConstraint,然后被添加到了MASCompositionConstraint中。
    现在MASCompositionConstraint有三个viewConstraint了。分别是top,left.bottom

    // MASCompositionConstraint.m 文件
    
    #pragma mark - attribute chaining
    
    - (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
        [self constraint:self addConstraintWithLayoutAttribute:layoutAttribute];
        return self;
    }
    #pragma mark - MASConstraintDelegate
    
    - (void)constraint:(MASConstraint *)constraint shouldBeReplacedWithConstraint:(MASConstraint *)replacementConstraint {
        NSUInteger index = [self.childConstraints indexOfObject:constraint];
        NSAssert(index != NSNotFound, @"Could not find constraint %@", constraint);
        [self.childConstraints replaceObjectAtIndex:index withObject:replacementConstraint];
    }
    
    - (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;
    }
    
    // make.m 文件
    - (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
        MASViewAttribute *viewAttribute = [[MASViewAttribute alloc] initWithView:self.view layoutAttribute:layoutAttribute];
        MASViewConstraint *newConstraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:viewAttribute];
        // 此时constraint = compositionConstraint,所以不会执行到这里
        if ([constraint isKindOfClass:MASViewConstraint.class]) {
            //replace with composite constraint
            NSArray *children = @[constraint, newConstraint];
            MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children];
            compositeConstraint.delegate = self;
            [self constraint:constraint shouldBeReplacedWithConstraint:compositeConstraint];
            return compositeConstraint;
        }
        // 此时constraint = compositionConstraint,所以不会执行到这里
        if (!constraint) {
            newConstraint.delegate = self;
            [self.constraints addObject:newConstraint];
        }
        // 执行这里,就是创建一个viewConstraint,然后返回viewConstraint
        return newConstraint;
    }
    

    make.top.right.bottom.mas_equalTo(20)的逻辑

    make.top.right.bottom前面返回了viewConstraint对象,然后执行mas_equal(20)

    // 抽象类MASConstraint.m中
    #pragma mark - NSLayoutRelation proxies
    
    - (MASConstraint * (^)(id))equalTo {
        return ^id(id attribute) {
            return self.equalToWithRelation(attribute, NSLayoutRelationEqual);
        };
    }
    
    //  具体实现类中 MASViewConstraint.m文件
    
    // 执行mas_equalTo,或者mas_greaterThanTo等方法,可以传递多种类型对象,例如某个view.mas_x,也可以是一个数组。
    // 如果是数组,就会进入`[attribute isKindOfClass:NSArray.class]`内部,
    // 然后将多个sectionAttribution创建成compositionConstraint存储起来。equalToWithRelation只是存储或替换数据,
    // 不会立刻执行,要通过install来执行。
    - (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;
            }
        };
    }
    
    

    接着要执行make.width.mas_equalTo(40)�;,逻辑和上边的一致。
    执行完毕后,要知道make.constraints中有1个compositionContraint,一个viewConstraint.compositionContraint放置了三个viewConstraint

    4.4 [make install]

    此时block函数全部执行完毕,现在接着执行[make install]函数

    // make.m 文件
    - (NSArray *)install {
      // 如果是re_make方法,就会执行这个
        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;
            // 具体是约束执行install方法
            [constraint install];
        }
        [self.constraints removeAllObjects];
        return constraints;
    }
    

    进入constraint文件查看具体install方法

    - (void)install {
        if (self.hasBeenInstalled) {
            return;
        }
        
        if ([self supportsActiveProperty] && self.layoutConstraint) {
            self.layoutConstraint.active = YES;
            [self.firstViewAttribute.view.mas_installedConstraints addObject:self];
            return;
        }
        
        // view1.attr1 = view2.attr2 * multiplier + constant
        
        MAS_VIEW *firstLayoutItem = self.firstViewAttribute.item;
        NSLayoutAttribute firstLayoutAttribute = self.firstViewAttribute.layoutAttribute;
        MAS_VIEW *secondLayoutItem = self.secondViewAttribute.item;
        NSLayoutAttribute secondLayoutAttribute = self.secondViewAttribute.layoutAttribute;
    
        // 对齐两个view必须有 secondViewAttribute
        // 如果没有secondViewAttribute,我们假设是superview
        // eg make.left.equalTo(@10)
        if (!self.firstViewAttribute.isSizeAttribute && !self.secondViewAttribute) {
            secondLayoutItem = self.firstViewAttribute.view.superview;
            secondLayoutAttribute = firstLayoutAttribute;
        }
        
        // 仅仅是创建layoutConstraint,还未应用
        MASLayoutConstraint *layoutConstraint
            = [MASLayoutConstraint constraintWithItem:firstLayoutItem
                                            attribute:firstLayoutAttribute
                                            relatedBy:self.layoutRelation
                                               toItem:secondLayoutItem
                                            attribute:secondLayoutAttribute
                                           multiplier:self.layoutMultiplier
                                             constant:self.layoutConstant];
        
        layoutConstraint.priority = self.layoutPriority;
        layoutConstraint.mas_key = self.mas_key;
        // 确定该约束应该作用到那个view上
        // 如果有secondViewAttribute.view 有可能调用的时候是make.left.equalTo(�otherView)
        if (self.secondViewAttribute.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);
            self.installedView = closestCommonSuperview;
        } else if (self.firstViewAttribute.isSizeAttribute) {
            // 如果是make.width.mas_equalTo(4);那么直接将约束安装到firstViewAttribute.view上
            self.installedView = self.firstViewAttribute.view;
        } else {
            self.installedView = self.firstViewAttribute.view.superview;
        }
    
    
        MASLayoutConstraint *existingConstraint = nil;
        // 仅仅是mas_update某个属性
        if (self.updateExisting) {
            existingConstraint = [self layoutConstraintSimilarTo:layoutConstraint];
        }
        if (existingConstraint) {
            // just update the constant
            existingConstraint.constant = layoutConstraint.constant;
            self.layoutConstraint = existingConstraint;
        } else {
            // 过去view上没有该约束,直接安装即可,并且将该约束添加到firstLayoutItem的已安装约束数组中,将来如果使用了mas_remake好去移除,mas_update好去寻找约束然后更新
            [self.installedView addConstraint:layoutConstraint];
            self.layoutConstraint = layoutConstraint;
            [firstLayoutItem.mas_installedConstraints addObject:self];
        }
    }
    

    至此设置view约束的代码就全部执行完毕。

    五.masonry提供的其他功能

    1.make提供了某个属性的设置,例如,left,right,top,bottom.也可以使用组合的方式来设置约束.

    @property (nonatomic, strong, readonly) MASConstraint *(^attributes)(MASAttribute attrs);
    
       [view1 mas_makeConstraints:^(MASConstraintMaker *make) {
            make.attributes(MASAttributeTop | MASAttributeLeft).mas_equalTo(133);
            make.attributes(MASAttributeBottom | MASAttributeRight).mas_equalTo(-133);
        }];
    

    2.查看当前view有哪些约束

    + (NSArray *)installedConstraintsForView:(MAS_VIEW *)view;
    

    六.设计亮点

    6.1 自定义添加了约束的优先级

    在已有的优先级基础上,在添加新的优先级。
    为了防止出错,直接使用过去的赋值。

        typedef UILayoutPriority MASLayoutPriority;
        static const MASLayoutPriority MASLayoutPriorityRequired = UILayoutPriorityRequired;
        static const MASLayoutPriority MASLayoutPriorityDefaultHigh = UILayoutPriorityDefaultHigh;
        static const MASLayoutPriority MASLayoutPriorityDefaultMedium = 500;
        static const MASLayoutPriority MASLayoutPriorityDefaultLow = UILayoutPriorityDefaultLow;
        static const MASLayoutPriority MASLayoutPriorityFittingSizeLevel = UILayoutPriorityFittingSizeLevel;
    
    6.2.firstViewAttribute && secondViewAttribute 相对灵活

    原生的布局的计算公式为,所以需要两个view。但是masonry假设只给定一个view(即firstViewAttribute)也行,另一个view根据某些给定的参数来确定。如果有了第二个view(secondViewAttribute)便可以直接布局了。
    但是这里的secondViewAttribute不一定是view,可以是其他的,masonry会根据实际情况来确定,然后布局的。
    secondViewAttribute 可以是NSValue,MAS_VIEW,MASViewAttribute,非常的灵活。

    6.3.用于判断view所安装的约束,采用了option来修饰MASAttribute属性
    typedef NS_OPTIONS(NSInteger, MASAttribute) {
        MASAttributeLeft = 1 << NSLayoutAttributeLeft,
        MASAttributeRight = 1 << NSLayoutAttributeRight,
        MASAttributeTop = 1 << NSLayoutAttributeTop,
        MASAttributeBottom = 1 << NSLayoutAttributeBottom,
        MASAttributeLeading = 1 << NSLayoutAttributeLeading,
        MASAttributeTrailing = 1 << NSLayoutAttributeTrailing,
        MASAttributeWidth = 1 << NSLayoutAttributeWidth,
        MASAttributeHeight = 1 << NSLayoutAttributeHeight,
        MASAttributeCenterX = 1 << NSLayoutAttributeCenterX,
        MASAttributeCenterY = 1 << NSLayoutAttributeCenterY,
        MASAttributeBaseline = 1 << NSLayoutAttributeBaseline,
    
        MASAttributeFirstBaseline = 1 << NSLayoutAttributeFirstBaseline,
        MASAttributeLastBaseline = 1 << NSLayoutAttributeLastBaseline,
        
    #if TARGET_OS_IPHONE || TARGET_OS_TV
        
        MASAttributeLeftMargin = 1 << NSLayoutAttributeLeftMargin,
        MASAttributeRightMargin = 1 << NSLayoutAttributeRightMargin,
        MASAttributeTopMargin = 1 << NSLayoutAttributeTopMargin,
        MASAttributeBottomMargin = 1 << NSLayoutAttributeBottomMargin,
        MASAttributeLeadingMargin = 1 << NSLayoutAttributeLeadingMargin,
        MASAttributeTrailingMargin = 1 << NSLayoutAttributeTrailingMargin,
        MASAttributeCenterXWithinMargins = 1 << NSLayoutAttributeCenterXWithinMargins,
        MASAttributeCenterYWithinMargins = 1 << NSLayoutAttributeCenterYWithinMargins,
    
    #endif
        
    };
    
    
    使用处
        NSAssert((attrs & anyAttribute) != 0, @"You didn't pass any attribute to make.attributes(...)");
        
        NSMutableArray *attributes = [NSMutableArray array];
        
        if (attrs & MASAttributeLeft) [attributes addObject:self.view.mas_left];
        if (attrs & MASAttributeRight) [attributes addObject:self.view.mas_right];
        if (attrs & MASAttributeTop) [attributes addObject:self.view.mas_top];
        if (attrs & MASAttributeBottom) [attributes addObject:self.view.mas_bottom];
        if (attrs & MASAttributeLeading) [attributes addObject:self.view.mas_leading];
        if (attrs & MASAttributeTrailing) [attributes addObject:self.view.mas_trailing];
        if (attrs & MASAttributeWidth) [attributes addObject:self.view.mas_width];
        if (attrs & MASAttributeHeight) [attributes addObject:self.view.mas_height];
        if (attrs & MASAttributeCenterX) [attributes addObject:self.view.mas_centerX];
        if (attrs & MASAttributeCenterY) [attributes addObject:self.view.mas_centerY];
        if (attrs & MASAttributeBaseline) [attributes addObject:self.view.mas_baseline];
        if (attrs & MASAttributeFirstBaseline) [attributes addObject:self.view.mas_firstBaseline];
        if (attrs & MASAttributeLastBaseline) [attributes addObject:self.view.mas_lastBaseline];
        
    #if TARGET_OS_IPHONE || TARGET_OS_TV
        
        if (attrs & MASAttributeLeftMargin) [attributes addObject:self.view.mas_leftMargin];
        if (attrs & MASAttributeRightMargin) [attributes addObject:self.view.mas_rightMargin];
        if (attrs & MASAttributeTopMargin) [attributes addObject:self.view.mas_topMargin];
        if (attrs & MASAttributeBottomMargin) [attributes addObject:self.view.mas_bottomMargin];
        if (attrs & MASAttributeLeadingMargin) [attributes addObject:self.view.mas_leadingMargin];
        if (attrs & MASAttributeTrailingMargin) [attributes addObject:self.view.mas_trailingMargin];
        if (attrs & MASAttributeCenterXWithinMargins) [attributes addObject:self.view.mas_centerXWithinMargins];
        if (attrs & MASAttributeCenterYWithinMargins) [attributes addObject:self.view.mas_centerYWithinMargins];
        
    #endif
    
    6.4.通过设置NSValue,自动判断类型&为属性设置数据
    #pragma mark - NSLayoutConstraint constant setter
    
    - (void)setLayoutConstantWithValue:(NSValue *)value {
        if ([value isKindOfClass:NSNumber.class]) {
            self.offset = [(NSNumber *)value doubleValue];
        } else if (strcmp(value.objCType, @encode(CGPoint)) == 0) {
            CGPoint point;
            [value getValue:&point];
            self.centerOffset = point;
        } else if (strcmp(value.objCType, @encode(CGSize)) == 0) {
            CGSize size;
            [value getValue:&size];
            self.sizeOffset = size;
        } else if (strcmp(value.objCType, @encode(MASEdgeInsets)) == 0) {
            MASEdgeInsets insets;
            [value getValue:&insets];
            self.insets = insets;
        } else {
            NSAssert(NO, @"attempting to set layout constant with unsupported value: %@", value);
        }
    }
    

    相关文章

      网友评论

        本文标题:Masonry代码解读

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