前言
UI布局是整個(gè)前端體系里不可或缺的一環(huán)。代碼的布局是設(shè)計(jì)語(yǔ)言與用戶視覺(jué)感受溝通的橋梁橄登,不論它看起來(lái)多么簡(jiǎn)單或是瑣碎轧膘,但不得不承認(rèn),絕大部分軟件開(kāi)發(fā)的問(wèn)題舟山,都是界面問(wèn)題绸狐。那么卤恳,如何高效的完成UI開(kāi)發(fā),也是軟件行業(yè)一直在克服的問(wèn)題寒矿。
所以突琳,軟件界面開(kāi)發(fā)的核心點(diǎn)即是:如何減少UI設(shè)計(jì)稿的建模難度和減少建模轉(zhuǎn)化到代碼的實(shí)現(xiàn)難度
最初iOS提供了平面直角坐標(biāo)系的方式,來(lái)解決布局問(wèn)題符相,即所謂的手動(dòng)布局拆融。平面直角坐標(biāo)系確實(shí)是一套完備在理論,這在數(shù)學(xué)上已經(jīng)驗(yàn)證過(guò)了啊终,只要我們的屏幕還是平面镜豹,它就肯定是有效的。但有效不一定高效蓝牲,我們?cè)谌粘5纳钪刑酥苌贂?huì)用平面直角坐標(biāo)系來(lái)向人描述位置關(guān)系。更多的是依靠相對(duì)位置搞旭。
所幸散怖,iOS為我們提供自動(dòng)布局的方法,來(lái)解決這一困境肄渗。
自動(dòng)布局的基本理念
其實(shí)說(shuō)到本質(zhì)镇眷,它和手動(dòng)布局是一樣的。對(duì)一個(gè)控件放在哪里翎嫡,我們依然只關(guān)心它的(x, y, width, height)
欠动。但手動(dòng)布局的方式是,一次性計(jì)算出這四個(gè)值惑申,然后設(shè)置進(jìn)去具伍,完成布局。但當(dāng)父控件或屏幕發(fā)生變化時(shí)圈驼,子控件的計(jì)算就要重新來(lái)過(guò)人芽,非常麻煩。
因此绩脆,在自動(dòng)布局中萤厅,我們不再關(guān)心(x, y, width, height)
的具體值,我們只關(guān)心(x, y, width, height)
四個(gè)量對(duì)應(yīng)的約束靴迫。
約束
那么何為約束呢惕味?
obj1.property1 =(obj2.property2 * multiplier)+ constant value
子控件的某一個(gè)量一定與另一個(gè)控件的某一個(gè)量呈線性關(guān)系,這就是約束玉锌。
那么名挥,給(x, y, width, height)
四個(gè)量,分別給一個(gè)約束主守,就可以確定一個(gè)控件的最終位置禀倔。
//創(chuàng)建左邊約束
NSLayoutConstraint *leftLc = [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:20];
[self.view addConstraint:leftLc];
這一段代碼即是:
控件(blueView)的 x = rootView的x * 1.0 + 20
這里一定要注意榄融,這樣的一條約束,涉及了子控件和父控件蹋艺,所以這條約束一定要添加到父控件中剃袍。
添加約束的規(guī)則:
- 如果兩個(gè)控件是父子控件,則添加到父控件中捎谨。
- 如果兩個(gè)控件不是父子控件,則添加到層級(jí)最近的共同父控件中憔维。
示例
//關(guān)閉Autoresizing
blueView.translatesAutoresizingMaskIntoConstraints = NO;
//創(chuàng)建左邊約束
NSLayoutConstraint *leftLc = [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:20];
[self.view addConstraint:leftLc];
//創(chuàng)建右邊約束
NSLayoutConstraint *rightLc = [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0 constant:-20];
[self.view addConstraint:rightLc];
//創(chuàng)建底部約束
NSLayoutConstraint *bottomLc = [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottom multiplier:1.0 constant:-20];
[self.view addConstraint:bottomLc];
//創(chuàng)建高度約束
NSLayoutConstraint *heightLc = [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:0.0 constant:50];
[blueView addConstraint: heightLc];
我們注意到涛救,自動(dòng)布局其實(shí)工作分兩步:
- 創(chuàng)建視圖的約束
- 將約束添加到合適的位置
約束關(guān)系從上面的描述中,已經(jīng)非常清晰了业扒。那么如何尋找約束添加的合適位置呢检吆?
到這里,我們只是解決了如何減少UI設(shè)計(jì)稿的建模難度的問(wèn)題程储,
顯然蹭沛,減少建模轉(zhuǎn)化到代碼的實(shí)現(xiàn)難度這個(gè)效果沒(méi)能達(dá)成。關(guān)于如何解決減少建模轉(zhuǎn)化到代碼的實(shí)現(xiàn)難度的問(wèn)題章鲤,
開(kāi)源庫(kù)
上面的代碼摊灭,我們可以看到,雖然自動(dòng)布局已經(jīng)比手動(dòng)布局優(yōu)雅不少了败徊,但它依然行數(shù)較多帚呼。每條約束大約都需要三行代碼,面對(duì)復(fù)雜的頁(yè)面皱蹦,這樣開(kāi)發(fā)出來(lái)煤杀,會(huì)很難閱讀。
Masonry則為我們解決了這個(gè)問(wèn)題沪哺。
引入Masonry
我們選擇使用Cocoapods的方式沈自。引入比較簡(jiǎn)單:
- 我們先在工程目錄下,創(chuàng)建Podfile文件:
2.編輯Podfile
其中辜妓,'IosOcDemo'就是我們工程的名字枯途,根據(jù)需要,我們自行替換嫌拣。
3.添加依賴
完成后柔袁,執(zhí)行指令pod install
。CocoaPods就會(huì)為我們自動(dòng)下載并添加依賴异逐。
實(shí)踐
這樣的一個(gè)代碼捶索,用手動(dòng)布局,我們大致的代碼應(yīng)該是這樣:
-(void)initBottomView
{
self.bottomBarView = [[UIView alloc]initWithFrame:CGRectZero];
self.bottomButtons = [[NSMutableArray alloc]init];
_bottomBarView.backgroundColor = [UIColor yellowColor];
[self addSubview:_bottomBarView];
for(int i = 0 ; i < 3 ; i++)
{
UIButton *button = [[UIButton alloc]initWithFrame:CGRectZero];
button.backgroundColor = [UIColor redColor];
[_bottomButtons addObject:button];
[self addSubview:button];
}
}
-(void)layoutBottomView
{
_bottomBarView.frame = CGRectMake(20, _viewHeight - 200, _viewWidth - 40, 200);
for (int i = 0 ; i < 3; i++) {
UIButton *button = _bottomButtons[i];
CGFloat x = i * (_viewWidth - 40 - 20 * 4) / 3 + 20*(i+1) + 20;
CGFloat y = _viewHeight - 200;
CGFloat width = (_viewWidth - 40 - 20 * 4) / 3;
CGFloat height = 200;
button.frame = CGRectMake(x, y, width, height);
}
}
我們來(lái)看一下灰瞻,在Masonry的幫助下腥例,我們可以把剛剛的代碼寫(xiě)成什么樣的:
-(void)initBottomView
{
_bottomBarView = [[UIView alloc]initWithFrame:CGRectZero];
_bottomBarView.backgroundColor = [UIColor yellowColor];
_bottomBarView.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_bottomBarView];
[_bottomBarView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self).with.offset(20);
make.right.equalTo(self).with.offset(-20);
make.height.mas_equalTo(200);
make.bottom.equalTo(self);
}];
_bottomButtons = [[NSMutableArray alloc]init];
for(int i = 0 ; i < 3 ; i++)
{
UIButton *button = [[UIButton alloc]initWithFrame: CGRectZero];
button.backgroundColor = [UIColor redColor];
button.translatesAutoresizingMaskIntoConstraints = NO;
[_bottomButtons addObject:button];
[_bottomBarView addSubview:button];
[button mas_makeConstraints:^(MASConstraintMaker *make) {
if (i == 0) {
make.left.mas_equalTo(20);
}else{
UIButton *previousButton = _bottomButtons[i-1];
make.left.equalTo(previousButton.mas_right).with.offset(20);
}
make.top.mas_equalTo(_bottomBarView.mas_top);
make.width.equalTo(_bottomBarView.mas_width).with.multipliedBy(1.0f/3).offset(-20*4/3);
make.height.equalTo(_bottomBarView.mas_height);
}];
}
}
我們可以看到在Masonry的封裝下辅甥,代碼變得非常簡(jiǎn)練易讀,需要行數(shù)略有增加燎竖,但是計(jì)算過(guò)程減少了,我們能更加關(guān)注于多個(gè)UIView間的位置關(guān)系构回,這與當(dāng)前的UI設(shè)計(jì)語(yǔ)言是契合的夏块。所以Masonry能否讓我們更直觀地表達(dá)UI。
源碼解讀
Masonry的封裝很有魅力纤掸,那么脐供,我們可以簡(jiǎn)單地來(lái)看一下,它是如何封裝的借跪。我們?cè)僮屑?xì)看一下Masonry的API會(huì)發(fā)現(xiàn)政己,我們是直接在UIView上進(jìn)行調(diào)用的。也就是說(shuō)掏愁,Masonry對(duì)UIView進(jìn)行了擴(kuò)展歇由。
在View+MASUtilities.h中:
#if TARGET_OS_IPHONE || TARGET_OS_TV
#import <UIKit/UIKit.h>
#define MAS_VIEW UIView
#define MAS_VIEW_CONTROLLER UIViewController
#define MASEdgeInsets UIEdgeInsets
然后在View+MASAdditions.h中,我們看到了Masonry的擴(kuò)展:
#import "MASUtilities.h"
#import "MASConstraintMaker.h"
#import "MASViewAttribute.h"
/**
* Provides constraint maker block
* and convience methods for creating MASViewAttribute which are view + NSLayoutAttribute pairs
*/
@interface MAS_VIEW (MASAdditions)
/**
* following properties return a new MASViewAttribute with current view and appropriate NSLayoutAttribute
*/
@property (nonatomic, strong, readonly) MASViewAttribute *mas_left;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_top;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_right;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_bottom;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_leading;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_trailing;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_width;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_height;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_centerX;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_centerY;
@property (nonatomic, strong, readonly) MASViewAttribute *mas_baseline;
@property (nonatomic, strong, readonly) MASViewAttribute *(^mas_attribute)(NSLayoutAttribute attr);
...
/**
* Creates a MASConstraintMaker with the callee view.
* Any constraints defined are added to the view or the appropriate superview once the block has finished executing
*
* @param block scope within which you can build up the constraints which you wish to apply to the view.
*
* @return Array of created MASConstraints
*/
- (NSArray *)mas_makeConstraints:(void(NS_NOESCAPE ^)(MASConstraintMaker *make))block;
一些果港,適配的代碼沦泌,我省略了,先看核心代碼京腥。在剛剛的例子中赦肃,我們正是調(diào)用的mas_makeConstraints
方法。
- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
self.translatesAutoresizingMaskIntoConstraints = NO;
MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
block(constraintMaker);
return [constraintMaker install];
}
mas_makeConstraints
方法比較簡(jiǎn)單公浪,只是封裝了MASConstraintMaker
初始化他宛,設(shè)置約束和安裝。這里的block就是我們剛剛在外層設(shè)置的約束的函數(shù)指針欠气。
也就是這一串:
^(MASConstraintMaker *make) {
make.left.equalTo(self.view).with.offset(10);
make.right.equalTo(self.view).with.offset(-10);
make.height.mas_equalTo(50);
make.bottom.equalTo(self.view).with.offset(-10);
}
由于約束條件的設(shè)置比較復(fù)雜厅各,我們先來(lái)看看初始化和安裝。
初始化
- (id)initWithView:(MAS_VIEW *)view {
self = [super init];
if (!self) return nil;
self.view = view;
self.constraints = NSMutableArray.new;
return self;
}
初始化的代碼比較簡(jiǎn)單预柒,將傳入的view放入MASConstraintMaker
成員队塘,然后創(chuàng)建MASConstraintMaker
的約束容器(NSMutableArray)。
安裝
- (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;
}
安裝的代碼分為三塊:
- 判斷是否需要移除已有的約束宜鸯。如果需要憔古,會(huì)遍歷已有約束,然后逐個(gè)
uninstall
-
copy
已有的約束淋袖,遍歷鸿市,并逐一install
-
remove
掉所有約束,并將已添加的constraints
返回。
install
的方法焰情,還是繼續(xù)封裝到了Constraint
中陌凳,我們繼續(xù)跟進(jìn)閱讀:
我們會(huì)發(fā)現(xiàn)Constraint
只是一個(gè)接口,Masonry中對(duì)于Constraint
接口有兩個(gè)實(shí)現(xiàn)内舟,分別是:MASViewConstraint
和MASCompositeConstraint
合敦。這兩個(gè)類,分別是單個(gè)約束和約束集合验游。
在上面的例子中充岛,我們只是對(duì)單個(gè)UIView
進(jìn)行約束,所以我們先看MASViewConstraint
的代碼批狱。
以下代碼MASViewConstraint
進(jìn)行了一定程度的簡(jiǎn)化裸准,省略了一些擴(kuò)展屬性,只展示我們的例子中赔硫,會(huì)執(zhí)行的代碼:
- (void)install {
if (self.hasBeenInstalled) {
return;
}
...
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
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;
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) {
self.installedView = self.firstViewAttribute.view;
} else {
self.installedView = self.firstViewAttribute.view.superview;
}
MASLayoutConstraint *existingConstraint = nil;
...
else {
[self.installedView addConstraint:layoutConstraint];
self.layoutConstraint = layoutConstraint;
[firstLayoutItem.mas_installedConstraints addObject:self];
}
}
自動(dòng)布局是一種相對(duì)布局,所以盐肃,絕大部分情況下爪膊,需要兩個(gè)UIView
(約束方與參照方)。在上面的方法中:
-
firstLayoutItem
是約束方砸王,secondLayoutItem
是參照方 -
firstLayoutAttribute
是約束方的屬性推盛,secondLayoutAttribute
是參照方的屬性。 -
MASLayoutConstraint
就是NSLayoutConstraint
的子類谦铃,只是添加了mas_key屬性耘成。
到這里,我們就與系統(tǒng)提供的API對(duì)應(yīng)上了驹闰。
NSLayoutConstraint *leftLc = [NSLayoutConstraint constraintWithItem:blueView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0 constant:20];
[self.view addConstraint:leftLc];
再看看我們之前用系統(tǒng)API完成的例子瘪菌,是不是格外熟悉?
那么接下來(lái)嘹朗,我們就是要閱讀
make.left.equalTo(self).with.offset(20);
make.right.equalTo(self).with.offset(-20);
make.height.mas_equalTo(200);
make.bottom.equalTo(self);
是如何變成firstLayoutItem
, secondLayoutItem
, firstLayoutAttribute
, secondLayoutAttribute
和layoutRelation
的师妙。
約束條件的設(shè)置
回到前面的:
- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
self.translatesAutoresizingMaskIntoConstraints = NO;
MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
block(constraintMaker);
return [constraintMaker install];
}
我們接下來(lái),就要看block的實(shí)現(xiàn):
block
其實(shí)是一個(gè)函數(shù)指針屹培。此處真正調(diào)用的方法是:
make.left.equalTo(self).with.offset(20);
make.right.equalTo(self).with.offset(-20);
make.height.mas_equalTo(200);
make.bottom.equalTo(self);
我們挑選其中一個(gè)默穴,來(lái)看看源碼實(shí)現(xiàn):
left
- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
return [self constraint:nil addConstraintWithLayoutAttribute:layoutAttribute];
}
- (MASConstraint *)left {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeLeft];
}
- (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
MASViewAttribute *viewAttribute = [[MASViewAttribute alloc] initWithView:self.view layoutAttribute:layoutAttribute];
MASViewConstraint *newConstraint = [[MASViewConstraint alloc] initWithFirstViewAttribute:viewAttribute];
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;
}
在對(duì)單個(gè)view
添加約束時(shí),constraint
為nil褪秀。我們直接生成了一個(gè)新約束newConstraint
蓄诽。它的firstViewAttribute
就是我們傳入的NSLayoutAttributeLeft
equalTo
- (MASConstraint * (^)(id))equalTo {
return ^id(id attribute) {
return self.equalToWithRelation(attribute, NSLayoutRelationEqual);
};
}
- (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;
}
};
}
此處,我們依然先看attribute不是NSArray
的情況媒吗。這里在單個(gè)屬性的約束中仑氛,就比較簡(jiǎn)單了,將relation
和attribue
傳入MASConstraint
對(duì)應(yīng)的成員蝴猪。
在上面介紹install
方法時(shí)调衰,我們就曾提到過(guò):
MASLayoutConstraint *layoutConstraint
= [MASLayoutConstraint constraintWithItem:firstLayoutItem
attribute:firstLayoutAttribute
relatedBy:self.layoutRelation
toItem:secondLayoutItem
attribute:secondLayoutAttribute
multiplier:self.layoutMultiplier
constant:self.layoutConstant];
firstLayoutItem
和secondLayoutItem
在install
方法中已收集完成膊爪,此時(shí),經(jīng)過(guò)left
和equalTo
我們又收集到了:firstViewAttribute
嚎莉、secondViewAttribute
和layoutRelation
勝利即在眼前米酬。
- (MASConstraint * (^)(CGFloat))offset {
return ^id(CGFloat offset){
self.offset = offset;
return self;
};
}
- (void)setOffset:(CGFloat)offset {
self.layoutConstant = offset;
}
通過(guò)OC的set語(yǔ)法,Masonry
將offset傳入layoutConstant趋箩。
至此赃额,layoutConstraint
就完成了全部的元素收集,可以使用添加約束的方式叫确,只需要解決最后一個(gè)問(wèn)題跳芳,約束添加到哪里呢?我們似乎在調(diào)用時(shí)竹勉,并不需要關(guān)心這件事情飞盆,那說(shuō)明框架幫我們完成了這個(gè)工作。
closestCommonSuperview
我們?cè)贛ASViewConstraint中次乓,可以找到這樣一段:
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) {
self.installedView = self.firstViewAttribute.view;
} else {
self.installedView = self.firstViewAttribute.view.superview;
}
注意到吓歇,closetCommonSuperview
就是Masonry為我們找到的最近公共父控件。
- (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;
}
實(shí)現(xiàn)也比較簡(jiǎn)單票腰。
至此城看,我們完成了所有準(zhǔn)備,就可以開(kāi)始愉快的自動(dòng)布局啦杏慰。
以上就是Masonry對(duì)iOS自動(dòng)布局封裝的解讀测柠。
如有問(wèn)題,歡迎指正缘滥。