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方法设置约束,从而达到通过点语法