iOS进阶之masonry细致入微(二)
2019-01-08 本文已影响0人
天蓬大元
在上篇文章中,我们了解到,当为某一个view添加约束时,masonry的代码执行顺序是下面这样的。我们通过细致的分析了解到一条约束在被装载到view之前,masonry都做了什么。其他三个约束的处理亦然。
self.translatesAutoresizingMaskIntoConstraints = NO;
MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
block(constraintMaker);
^(MASConstraintMaker *make) {
make.left.mas_equalTo(lable.superview.mas_left).offset(10);
make.right.mas_equalTo(-10);
make.top.mas_equalTo(0);
make.bottom.mas_equalTo(0);
}
return [constraintMaker install];
我们这篇文章主要讲述,如何将存储在MASConstraintMaker对象中的约束装载到view上。在开始之前,我们简短的回顾一个约束的收集过程。
1,创建一个MASConstraintMaker类对象爱丽丝,她持有要添加约束view乔治,并且持有一个数组,用来收集约束。
2,爱丽丝通过.left创建一个MASViewConstraint类对象葛二蛋,葛二蛋持有了left约束条件,并被保存在爱丽丝的数组中。
3,葛二蛋通过mas_equalTo获取到相对于父类的约束并存储
4,葛二蛋通过offset获取到子类与父类约束之间的改变值。
.right和.top和.bottom的处理情况与.left类似。
至此,葛二蛋兄弟4个持有了乔治所有的约束条件,而爱丽丝持有了乔治和葛二蛋兄弟4个。那接下来就是爱丽丝如何将二蛋四兄弟装载到乔治身上,完成约束的添加任务。
好,我们开始进入正题:[constraintMaker install]。
- (NSArray *)install {
///注意这里的self指代的是谁。
///这个是干什么的,我们先不管,你只要知道这里if的代码不会被执行
if (self.removeExisting) {
NSArray *installedConstraints = [MASViewConstraint installedConstraintsForView:self.view];
for (MASConstraint *constraint in installedConstraints) {
[constraint uninstall];
}
}
///你不应该还不知道这里的self是谁。
NSArray *constraints = self.constraints.copy;
for (MASConstraint *constraint in constraints) {
///取出来的就是二蛋4兄弟之一
constraint.updateExisting = self.updateExisting;
///调用了葛二蛋的装载方法。
[constraint install];
}
///爱丽丝的数组被清空,但constraints仍然保存了一份二蛋4兄弟。这里你应该知道copy的用法。体会这里作者为什么用copy处理一下数组。
[self.constraints removeAllObjects];
///返回了二蛋4兄弟,注意,此时爱丽丝没有再持有这四兄弟。
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;
}
MAS_VIEW *firstLayoutItem = self.firstViewAttribute.item;
///这个是要添加约束的view的自己的约束项
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)
///这里作者的注释已经写的很清楚了,如果你写出了make.left.equalTo(@10)这样的约束,就会用到这个处理,自动获取父类,并让父类的对比约束和子类一样。
if (!self.firstViewAttribute.isSizeAttribute && !self.secondViewAttribute) {
///父类
secondLayoutItem = self.firstViewAttribute.view.superview;
///父类的约束条件取子类的约束条件
secondLayoutAttribute = firstLayoutAttribute;
}
///好,接下来的代码就是核心中的核心了。调用系统的autolayout进行约束处理。MASLayoutConstraint继承自NSLayoutConstraint。扩展了一个有意思的key,你能体会到这个key的用处吗?如果你不数熟悉autolayout的API,记得了解一下,这里不做过多解释。你可以不用,但你最好知道。
MASLayoutConstraint *layoutConstraint
= [MASLayoutConstraint constraintWithItem:firstLayoutItem
attribute:firstLayoutAttribute
relatedBy:self.layoutRelation
toItem:secondLayoutItem
attribute:secondLayoutAttribute
multiplier:self.layoutMultiplier
constant:self.layoutConstant];
///其实看到这里,你就应该思索,masonry的功能,不仅仅是添加普通约束。
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);
///关键理解这个。这里还是要说,你真的需要理解一下autolayout是如何进行布局的。公共父类进行布局约束。
self.installedView = closestCommonSuperview;
} else if (self.firstViewAttribute.isSizeAttribute) {
/**///了解了这个,就好理解这里的判断了。
- (BOOL)isSizeAttribute {
return self.layoutAttribute == NSLayoutAttributeWidth
|| self.layoutAttribute == NSLayoutAttributeHeight;
}
*/
self.installedView = self.firstViewAttribute.view;
} else {
///view相对于view.superView进行布局
self.installedView = self.firstViewAttribute.view.superview;
}
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];
}
}