Masonry
使用
- 關鍵方法:
- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *make))block;
- 約束方法除了equalTo,還有lessThanOrEqualTo和greaterThanOrEqualTo
- 當已有約束需要更新時調用
mas_updateConstraints
方法mas_remakeConstraints
方法會先清除當前所有約束再布置- Masonry的五大參數:
Attribute(屬性) ,Relation(關系),Multiplier(乘),Constant(大小),Priority(優先級)
//一個系統的約束創建方法
[NSLayoutConstraint constraintWithItem:view1
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:superview
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:padding.top]
//mas_makeConstraints
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(superView).with.offset(10);
make.left.equalTo(superView).with.offset(10);
make.bottom.equalTo(superView.mas_bottom).with.offset(-10);
make.right.equalTo(superView.mas_right).with.offset(-10);
// 等價于
// make.edges.equalTo(superView).with.insets(UIEdgeInsetsMake(10, 10, 10, 10));
// 會自動調用view1.translatesAutoresizingMaskIntoConstraints = NO;
}];
//mas_remakeConstrains
[self.button mas_remakeConstraints:^(MASConstraintMaker *make) {
make.size.equalTo(self.buttonSize);
if (topLeft) {
make.top.and.left.offset(10);
} else {
make.bottom.and.right.offset(-10);
}
}];
//mas_updateConstraints
[self.growingButton mas_updateConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self);
make.width.equalTo(@(self.buttonSize.width)).priorityLow();
make.height.equalTo(@(self.buttonSize.height)).priorityLow();
make.width.lessThanOrEqualTo(self);
make.height.lessThanOrEqualTo(self);
}];
//according to apple super should be called at end of method
[super updateConstraints];
}
原理
- mas_makeConstraints方法內部創建MASConstraintMaker對象,然后傳遞到block執行,完成后調用maker的install方法來確保約束被添加到視圖中
//設置約束方法
- (NSArray *)mas_updateConstraints:(void(^)(MASConstraintMaker *))block {
self.translatesAutoresizingMaskIntoConstraints = NO;
MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
constraintMaker.updateExisting = YES;
block(constraintMaker);
return [constraintMaker install];
}
//MASConstraintMaker的install方法
- (NSArray *)install {
//判斷是否有移除所有已存在的約束標志
if (self.removeExisting) {
NSArray *installedConstraints = [MASViewConstraint installedConstraintsForView:self.view];
for (MASConstraint *constraint in installedConstraints) {
[constraint uninstall];
}
}
//取出maker對象中的所有約束
NSArray *constraints = self.constraints.copy;
for (MASConstraint *constraint in constraints) {
//設置已經設置了約束的標志
constraint.updateExisting = self.updateExisting;
//調用MASConstraint的install方法
[constraint install];
}
[self.constraints removeAllObjects];
return constraints;
}
//MASViewConstraint(MASConstraint子類)的install方法
- (void)install {
...
...
MASLayoutConstraint *layoutConstraint
= [MASLayoutConstraint constraintWithItem:firstLayoutItem
attribute:firstLayoutAttribute
relatedBy:self.layoutRelation
toItem:secondLayoutItem
attribute:secondLayoutAttribute
multiplier:self.layoutMultiplier
constant:self.layoutConstant];
...
...
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];
}
}
MASConstraint和其子類
- MASConstraint提供了基礎屬性(left,top,leftMargin...),且是創建鏈式語法的必要要素
- MASCompositeConstraint內有一個childConstraints的屬性,在布局的時候,會遍歷該數組,逐一進行install方法調用,make.edges,make.size返回的就是該類型
- MASViewConstraint是承載支持AutoLayout真正的對象,他創建了一個NSLayoutConstraint的必要屬性,并將其添加到對應的view上;它的firstViewAttribute和secondViewAttribute屬性分別代表了對應要設置約束兩個view的屬性
Masonry鏈式語法實現原理
進入文件中可發現left,top..等maker屬性方法返回都是MASConstraint類型,而MASConstraint中也有這些相同的屬性方法,返回值依是MASCompositeConstraint對象,所有才能像
make.top.left.right...
這樣使用Masonry,具體實現原理如下
1、MASConstraint的left方法:
- (MASConstraint *)left {
return [self addConstraintWithLayoutAttribute:NSLayoutAttributeLeft];
}
它會跳轉到MASViewConstraint的addConstraintWithLayout...方法
--------------------------------------------
2、MASViewConstraint的addConstraintWithLayout...方法
- (MASConstraint *)addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
return [self.delegate constraint:self addConstraintWithLayoutAttribute:layoutAttribute];
}
它會調用delegate的constraint...delegate就是MASConstraintMaker,來看看吧
--------------------------------------------
3、MASConstraintMaker的代理方法
- (MASConstraint *)constraint:(MASConstraint *)constraint addConstraintWithLayoutAttribute:(NSLayoutAttribute)layoutAttribute {
MASCompositeConstraint *compositeConstraint = [[MASCompositeConstraint alloc] initWithChildren:children];
[self constraint:constraint shouldBeReplacedWithConstraint:compositeConstraint];
return compositeConstraint;
}
創建的compositeConstraint布局時,就會調用children的install方法設置約束,從而達到通過點語法