Masonry代碼解讀

一.前言

Masonry是非常有名的布局框架,今天我們就分析它的具體實現(xiàn)。通讀了一邊源碼,寫的非常的好,有很多值得我們學(xué)習(xí)的地方。

二.前期準備

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中使用了該設(shè)計模式。

三.整體結(jié)構(gòu)圖 & 各類提供的作用

Masonry架構(gòu)圖
  • 1.View+MASAdditions.h
    UIView(如果是macOS,則為NSView)提供創(chuàng)建make的方法,方便實現(xiàn)布局。并且提供當前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方法,都是創(chuàng)建一個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;
    
    // 組合約束屬性,用于一次性創(chuàng)建多個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;
    
    // 將約束設(shè)置到view上
    - (NSArray *)install;
    
  • 3.MASConstraint
    特別注意:是一個抽象類,聲明方法和屬性,不實現(xiàn)具體的方法,都要子類實現(xiàn)?。?!
    并且聲明了一下方法,使鏈式編程變?yōu)榭赡堋?/p>

    // 聲明get方法,用于創(chuàng)建MASConstraint,然后添加到make的數(shù)組中。通過Constraint的addConstraintWithLayoutAttribute來添加,具體邏輯由子類實現(xiàn)。
    - (MASConstraint *)left;
    - (MASConstraint *)top;
    - (MASConstraint *)right;
    - (MASConstraint *)bottom;
    - (MASConstraint *)leading;
    - (MASConstraint *)trailing;
    - (MASConstraint *)width;
    - (MASConstraint *)height;
    - (MASConstraint *)centerX;
    - (MASConstraint *)centerY;
    - (MASConstraint *)baseline;
    
    // 為constraint添加屬性或equal關(guān)系,然后返回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,實現(xiàn)抽象類的方法。是對約束所需要所有屬性的封裝。

在組合模式中,屬于葉子節(jié)點!?。〔豢梢蕴砑幼庸?jié)點。Masonry中如果想讓葉子節(jié)點變?yōu)闃渲?jié)點,會將兩個葉子節(jié)點放到一個數(shù)組中,然后創(chuàng)建一個樹枝節(jié)點,然后用樹枝節(jié)點替換葉子節(jié)點的位置。

// 布局公式:view1.attr1 = view2.attr2 * multiplier + constant 

// view1的各個屬性參數(shù)
@property (nonatomic, strong, readonly) MASViewAttribute *firstViewAttribute;
// view2的各個屬性參數(shù),secondViewAttribute可以是NSValue,UIView,MASViewAttribute,提供了較多的方式,后續(xù)會分析
@property (nonatomic, strong, readonly) MASViewAttribute *secondViewAttribute;
// 某個view已安裝的約束
+ (NSArray *)installedConstraintsForView:(MAS_VIEW *)view;

 // .m文件實現(xiàn)方法
- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute;
// 非常重要的方法
- (void)install;
  • 5.MASCompositeConstraint
    繼承于MASConstraint,實現(xiàn)抽象類的方法。內(nèi)部維護一個數(shù)組,全部都是MASViewConstraint對象。

    在組合模式中,是樹枝節(jié)點,內(nèi)部維護一個數(shù)組,可以添加葉子節(jié)點。

    // .h 文件
    - (id)initWithChildren:(NSArray *)children;
    // .m 文件中實現(xiàn)了抽象類的方法
    基本上就是for循環(huán)變量MASViewConstraint,然后執(zhí)行對應(yīng)名稱的方法而已。唯一特別的就是它可以add葉子節(jié)點?。?!
    
    #pragma mark - MASConstraintDelegate   稍后分析
    
    - (void)constraint:(MASConstraint *)constraint shouldBeReplacedWithConstraint:(MASConstraint *)replacementConstraint;
    - (MASConstraint *)constraint:(MASConstraint __unused *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute;
    
  • 6.MASConstraint+Private.h
    聲明了MASConstraintDelegate代理方法。
    MASCompositeConstraintMASConstraintMaker實現(xiàn)的。

    @protocol MASConstraintDelegate <NSObject>
    
    //  當組合模式中,要將葉子節(jié)點替換為樹枝節(jié)點,使用此方法
    - (void)constraint:(MASConstraint *)constraint shouldBeReplacedWithConstraint:(MASConstraint *)replacementConstraint;
    
    // 將葉子節(jié)點添加到組合模式中
    - (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute;
    
    @end
    
關(guān)系圖&委托關(guān)系

四.Masonsy 如何工作的

下面通過代碼來看看Masonry是如何運作的,代碼如下:

[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.left.bottom.mas_equalTo(20);
        make.width.mas_equalTo(40)?;
 }];
4.1創(chuàng)建make對象,執(zhí)行block
- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
    // a.關(guān)閉轉(zhuǎn)換AutoresizingMask至Constraints的屬性
    self.translatesAutoresizingMaskIntoConstraints = NO;
    // b.創(chuàng)建make,用weak保存self(設(shè)置約束的view)
    MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
    // c.執(zhí)行block,make.top.left.bottom.mas_equalTo(20); && make.width.mas_equalTo(40)?;
    block(constraintMaker);
    // d.執(zhí)行install操作
    return [constraintMaker install];
}
4.2 block(constraintMaker);

這里執(zhí)行make.top語句,即:

// make.x 直接返回MASConstraint對象
- (MASConstraint *)top {
    return [self addConstraintWithLayoutAttribute:NSLayoutAttributeTop];
}

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

#pragma mark - MASConstraintDelegate 實現(xiàn)的代理方法

- (void)constraint:(MASConstraint *)constraint shouldBeReplacedWithConstraint:(MASConstraint *)replacementConstraint {
   // 如果將viewConstraint替換為compositionConstaint,調(diào)用此方法
    NSUInteger index = [self.constraints indexOfObject:constraint];
    NSAssert(index != NSNotFound, @"Could not find constraint %@", constraint);
    [self.constraints replaceObjectAtIndex:index withObject:replacementConstraint];
}

// 該方法是將樹枝節(jié)點或者是葉子節(jié)點直接存放到make.constraints數(shù)組中
- (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
    // 如果是make.x 的時候,constraint = nil,就是創(chuàng)建一個MASViewConstraint
    MASViewAttribute *viewAttribute = [[MASViewAttribute alloc] initWithView:self.view layoutAttribute:layoutAttribute];
    MASViewConstraint *newConstraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:viewAttribute];
    if ([constraint isKindOfClass:MASViewConstraint.class]) {
        // 將MASViewConstraint 變成MASCompositeConstraint使用調(diào)用。
        // make.top.left的時候會執(zhí)行到這里 ,make.top.left.bottom也會執(zhí)行到這里。實際上就是MASCompositeConstraint存放了三個MASViewConstraint。
        // MASCompositeConstraint放置在make.constraints數(shù)組中。典型的組合模式
        NSArray *children = @[constraint, newConstraint];
        MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children];
        compositeConstraint.delegate = self;
        [self constraint:constraint shouldBeReplacedWithConstraint:compositeConstraint];
        return compositeConstraint;
    }
    // 當前make.top會執(zhí)行這里newConstraint = topConstraint,將topConstraint.delegate = self(make)
    if (!constraint) {
        newConstraint.delegate = self;
        [self.constraints addObject:newConstraint];
    }
    return newConstraint;
}

這里執(zhí)行make.top.left語句,剛才通過make.top返回了MASViewConstraint對象,現(xiàn)在看看MASViewConstraint.left的函數(shù)實現(xiàn)

// 重寫父類方法
#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參數(shù)調(diào)用了代理方法,此時self.delegate = make
    return [self.delegate constraint:self addConstraintWithLayoutAttribute:layoutAttribute];
}

此時會調(diào)用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;
    }
    //下面代碼不會執(zhí)行
    if (!constraint) {
        newConstraint.delegate = self;
        [self.constraints addObject:newConstraint];
    }
    return newConstraint;
}

執(zhí)行make.top.left.bottom代碼
會執(zhí)行MASCompositionConstraint.bottom方法。
該代碼的含義,就是創(chuàng)建了bottomViewConstraint,然后被添加到了MASCompositionConstraint中。
現(xiàn)在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,所以不會執(zhí)行到這里
    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,所以不會執(zhí)行到這里
    if (!constraint) {
        newConstraint.delegate = self;
        [self.constraints addObject:newConstraint];
    }
    // 執(zhí)行這里,就是創(chuàng)建一個viewConstraint,然后返回viewConstraint
    return newConstraint;
}

make.top.right.bottom.mas_equalTo(20)的邏輯

make.top.right.bottom前面返回了viewConstraint對象,然后執(zhí)行mas_equal(20)

// 抽象類MASConstraint.m中
#pragma mark - NSLayoutRelation proxies

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

//  具體實現(xiàn)類中 MASViewConstraint.m文件

// 執(zhí)行mas_equalTo,或者mas_greaterThanTo等方法,可以傳遞多種類型對象,例如某個view.mas_x,也可以是一個數(shù)組。
// 如果是數(shù)組,就會進入`[attribute isKindOfClass:NSArray.class]`內(nèi)部,
// 然后將多個sectionAttribution創(chuàng)建成compositionConstraint存儲起來。equalToWithRelation只是存儲或替換數(shù)據(jù),
// 不會立刻執(zhí)行,要通過install來執(zhí)行。
- (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;
        }
    };
}

接著要執(zhí)行make.width.mas_equalTo(40)?;,邏輯和上邊的一致。
執(zhí)行完畢后,要知道make.constraints中有1個compositionContraint,一個viewConstraint.compositionContraint放置了三個viewConstraint。

4.4 [make install]

此時block函數(shù)全部執(zhí)行完畢,現(xiàn)在接著執(zhí)行[make install]函數(shù)

// make.m 文件
- (NSArray *)install {
  // 如果是re_make方法,就會執(zhí)行這個
    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;
        // 具體是約束執(zhí)行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,我們假設(shè)是superview
    // eg make.left.equalTo(@10)
    if (!self.firstViewAttribute.isSizeAttribute && !self.secondViewAttribute) {
        secondLayoutItem = self.firstViewAttribute.view.superview;
        secondLayoutAttribute = firstLayoutAttribute;
    }
    
    // 僅僅是創(chuàng)建layoutConstraint,還未應(yīng)用
    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;
    // 確定該約束應(yīng)該作用到那個view上
    // 如果有secondViewAttribute.view 有可能調(diào)用的時候是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的已安裝約束數(shù)組中,將來如果使用了mas_remake好去移除,mas_update好去尋找約束然后更新
        [self.installedView addConstraint:layoutConstraint];
        self.layoutConstraint = layoutConstraint;
        [firstLayoutItem.mas_installedConstraints addObject:self];
    }
}

至此設(shè)置view約束的代碼就全部執(zhí)行完畢。

五.masonry提供的其他功能

1.make提供了某個屬性的設(shè)置,例如,left,right,top,bottom.也可以使用組合的方式來設(shè)置約束.

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

六.設(shè)計亮點

6.1 自定義添加了約束的優(yōu)先級

在已有的優(yōu)先級基礎(chǔ)上,在添加新的優(yōu)先級。
為了防止出錯,直接使用過去的賦值。

    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假設(shè)只給定一個view(即firstViewAttribute)也行,另一個view根據(jù)某些給定的參數(shù)來確定。如果有了第二個view(secondViewAttribute)便可以直接布局了。
但是這里的secondViewAttribute不一定是view,可以是其他的,masonry會根據(jù)實際情況來確定,然后布局的。
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.通過設(shè)置NSValue,自動判斷類型&為屬性設(shè)置數(shù)據(jù)
#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);
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容