iOS Masonry—最优美的自动布局框架-实现原理
2017-06-19 本文已影响0人
Onlyoner
在做需求的时候为了完美的适配各种尺寸的屏幕,我们往往需要做大量的适配工作,有了Masonry之后使我们的适配工作减轻了不少,出了Masonry还有一个优秀的框架国内SDAutoLayout
小对比:
UIView *view = UIView.new;
[self.view addSubview:view]
SDAutoLayout:
view.sd_layout.leftSpaceToView(self.view, 20).bottomSpaceToView(self.view, 20).widthIs(100).heightIs(100);
Masonry:
[view mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.offset(20);
make.top.offset(100);
make.height.equalTo(@100);
make.right.equalTo(view1.mas_left).with.offset(-100);
}];
我们项目中两种都有使用,各有千秋结合起来更能事半功倍:
下边从Masonry说起:
集成框架到项目【cocoaPods】【直接将文件夹拖入】两种方式
#import "ViewController.h"
#import "Masonry.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//1⃣️创建一个上下左右距离10的view
UIView *redview = [[UIView alloc] init];
redview.backgroundColor = [UIColor redColor];
[self.view addSubview:redview];
//2⃣️添加约束
//make 约束制造者
/*
补充小知识:
10不是对象,加个@10,会将其转化成对象[NSNumber numberWithInt:10],@就是一种简便写法,
如@[]代表数组,@{}代表NSDictionary
*/
[redview mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.top.equalTo(@10);
make.bottom.right.equalTo(@-10);
/*
mas_makeConstraints执行流程:
1、创建约束制造者 MASConstraintMaker 并且绑定控件
2、执行mas_makeConstraints传入的Block
3、让约束制造者安装约束
*3.1、清空之前所有约束
* 3.2、遍历约束数组,一个一个安装
*/
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
Simulator Screen Shot 2017年6月19日 下午7.07.50.png
实现原理也就是 mas_makeConstraints执行流程:
mas_makeConstraints:
" cmd "点"mas_makeConstraints"进去
" [redview mas_makeConstraints:^(MASConstraintMaker *make) {}]"
创建约束制造者 MASConstraintMaker 并且绑定控件
- (NSArray *)mas_makeConstraints:(void(^)(MASConstraintMaker *))block {
self.translatesAutoresizingMaskIntoConstraints = NO;
MASConstraintMaker *constraintMaker = [[MASConstraintMaker alloc] initWithView:self];
block(constraintMaker);
return [constraintMaker install];
}
执行mas_makeConstraints传入的Block
block(constraintMaker);
把MASConstraintMaker传过去其实就是make
让约束制造者安装约束
[constraintMaker install]安装约束
一进去就去清空之前所有约束
- (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;
}
遍历约束数组,一个一个安装
MASViewConstraint
[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;
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)
if (!self.firstViewAttribute.isSizeAttribute && !self.secondViewAttribute) {
secondLayoutItem = self.firstViewAttribute.view.superview;
secondLayoutAttribute = firstLayoutAttribute;
}
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;
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);
self.installedView = closestCommonSuperview;
} 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];
}
}
这一堆就是Masonry帮我们写的自动布局的代码,这段相当恶心,把它藏在这里,以后调用的时候就不用写这段代码了。
至此自动布局的安装完成所有的约束
那么什么是链式编程思想?
链式编程的思想:方法的返回值必须要有 “方法调用者”
才能一直点"."下去
[redview mas_makeConstraints:^(MASConstraintMaker *make) {
//设置约束 每次调用left/top就是将约束添加到数组中
/*
make.left.top.equalTo(@10);
make.bottom.right.equalTo(@-10);
*/
以上这两句就相当于下边:
MASConstraint * (^block)(id) = make.top.left.equalTo;
MASConstraint *mk = block(@10);
mk.left.top.equalTo(@10);
}];