一.前言
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)圖 & 各類提供的作用

-
1.
View+MASAdditions.h
為UIView(如果是macOS,則為NSView)提供創(chuàng)建make的方法,方便實現(xiàn)布局。并且提供當前view的mas_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代理方法。
由MASCompositeConstraint和MASConstraintMaker實現(xiàn)的。@protocol MASConstraintDelegate <NSObject> // 當組合模式中,要將葉子節(jié)點替換為樹枝節(jié)點,使用此方法 - (void)constraint:(MASConstraint *)constraint shouldBeReplacedWithConstraint:(MASConstraint *)replacementConstraint; // 將葉子節(jié)點添加到組合模式中 - (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創(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);
}
}