OC 常用的約束框架是Masonry
勾拉,而swift
常用的是SnapKit
衅澈,不過(guò)今天就只看看Masonry
他巨。
先看個(gè)例子:
[view mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.offset(0);
make.top.offset(0);
make.right.offset(0);
make.height.offset(300);
}];
[lable mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.offset(600);
make.left.offset(100);
}];
[button mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(view.mas_bottom).offset(10);
make.left.equalTo(view);
make.height.offset(50);
make.width.offset(50);
}];
- 源碼
- 首先來(lái)看
mas_makeConstraints
澡匪,內(nèi)部初始化MASConstraintMaker
,然后用block
送出去操作:
#define MAS_VIEW UIView
@implementation MAS_VIEW (MASAdditions)
- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
self.translatesAutoresizingMaskIntoConstraints = NO;
MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
block(constraintMaker);
return [constraintMaker install];
}
- 然后先回到外面來(lái)拆融,看一下
make.left
(right,top,height
等等都一樣)拆座,最終MASConstraintMaker
的操作都會(huì)加到約束數(shù)組中:
@implementation MASConstraintMaker
- (MASConstraint *)left {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeLeft];
}
- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
return [self constraint:nil addConstraintWithLayoutAttribute:layoutAttribute];
}
- (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
...
if (!constraint) {
newConstraint.delegate = self;
[self.constraints addObject:newConstraint];//添加到數(shù)組
}
return newConstraint;
}
- 添加到約束數(shù)組之后返回了
MASConstraint
,接著來(lái)看看equalTo
冠息,offset
:
- (MASConstraint * (^)(id))equalTo {
return ^id(id attribute) {
return self.equalToWithRelation(attribute, NSLayoutRelationEqual);
};
}
- (MASConstraint * (^)(CGFloat))offset {
return ^id(CGFloat offset){
self.offset = offset;
return self;
};
}
-
equalTo
,offset
其實(shí)都是block
形式孕索,所以調(diào)用時(shí)可以用()
而不用[]
逛艰,而且都返回MASConstraint
,所以可以連續(xù)調(diào)用搞旭,緊接著make.left
使用鏈?zhǔn)秸Z(yǔ)法散怖。
-
block(constraintMaker)
執(zhí)行完后,就進(jìn)行[constraintMaker install]
:
@implementation MASConstraintMaker
- (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ì)先判斷self.removeExisting
移除舊約束肄渗,再遍歷約束數(shù)組進(jìn)行[constraint install]
:
- (void)install {
...
//MASLayoutConstraint 繼承于 NSLayoutConstraint
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;
//找出約束添加到哪個(gè)view上镇眷,并賦值給self.installedView
//self.firstViewAttribute.view是要約束的view,self.secondViewAttribute.view是作為參考的view
if (self.secondViewAttribute.view) {
MAS_VIEW *closestCommonSuperview = [self.firstViewAttribute.view mas_closestCommonSuperview:self.secondViewAttribute.view];
self.installedView = closestCommonSuperview;//第一個(gè)和第二個(gè)view共同最近的一個(gè)superView
} else if (self.firstViewAttribute.isSizeAttribute) {
self.installedView = self.firstViewAttribute.view;//如果約束寬高翎嫡,則自己添加約束
} else {
self.installedView = self.firstViewAttribute.view.superview;//默認(rèn)父控件
}
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];
}
}
添加約束的控件默認(rèn)是父控件欠动,如果固定寬高則為自身,如果有self.secondViewAttribute.view
則找出共同父控件,最終判斷self.updateExisting
給控件添加約束或者更新約束具伍。
- 另外翅雏,上面出現(xiàn)的
self.updateExisting
會(huì)在mas_updateConstraints
里設(shè)置雕欺,self.removeExisting
會(huì)在mas_remakeConstraints
里設(shè)置:
- (NSArray *)mas_updateConstraints:(void(^)(MASConstraintMaker *))block {
self.translatesAutoresizingMaskIntoConstraints = NO;
MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
constraintMaker.updateExisting = YES;
block(constraintMaker);
return [constraintMaker install];
}
- (NSArray *)mas_remakeConstraints:(void(^)(MASConstraintMaker *make))block {
self.translatesAutoresizingMaskIntoConstraints = NO;
MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
constraintMaker.removeExisting = YES;
block(constraintMaker);
return [constraintMaker install];
}
- 總結(jié)
mas_makeConstraints
會(huì)返回該View
的約束數(shù)組恋沃,通過(guò)block
傳送MASConstraintMaker
(負(fù)責(zé)管理約束)添加約束,block
完畢后掰茶,
MASConstraintMaker
調(diào)用install
萤厅,然后會(huì)遍歷約束數(shù)組橄抹,每一個(gè)MASViewConstraint
都調(diào)用install
,最終會(huì)調(diào)用原生的方法添加約束惕味。