OC 常用的约束框架是Masonry
,而swift
常用的是SnapKit
,不过今天就只看看Masonry
。
先看个例子:
[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);
}];
- 源码
- 首先来看
mas_makeConstraints
,内部初始化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];
}
- 然后先回到外面来,看一下
make.left
(right,top,height
等等都一样),最终MASConstraintMaker
的操作都会加到约束数组中:
@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];//添加到数组
}
return newConstraint;
}
- 添加到约束数组之后返回了
MASConstraint
,接着来看看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
其实都是block
形式,所以调用时可以用()
而不用[]
,而且都返回MASConstraint
,所以可以连续调用,紧接着make.left
使用链式语法。
-
block(constraintMaker)
执行完后,就进行[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;
}
会先判断self.removeExisting
移除旧约束,再遍历约束数组进行[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;
//找出约束添加到哪个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;//第一个和第二个view共同最近的一个superView
} else if (self.firstViewAttribute.isSizeAttribute) {
self.installedView = self.firstViewAttribute.view;//如果约束宽高,则自己添加约束
} else {
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];
}
}
添加约束的控件默认是父控件,如果固定宽高则为自身,如果有self.secondViewAttribute.view
则找出共同父控件,最终判断self.updateExisting
给控件添加约束或者更新约束。
- 另外,上面出现的
self.updateExisting
会在mas_updateConstraints
里设置,self.removeExisting
会在mas_remakeConstraints
里设置:
- (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];
}
- 总结
mas_makeConstraints
会返回该View
的约束数组,通过block
传送MASConstraintMaker
(负责管理约束)添加约束,block
完毕后,
MASConstraintMaker
调用install
,然后会遍历约束数组,每一个MASViewConstraint
都调用install
,最终会调用原生的方法添加约束。

网友评论