习惯使用AutoLayout进行适配的人可能上手Masonary会非常迅速,下面简要的讲述一下Masonary适配的思路
OC版:
github地址:https://github.com/SnapKit/Masonry
Swift版
github地址:https://github.com/SnapKit/SnapKit
下面的代码是一个自定义View,并且对自定义View中的自控件进行布局。
- (void)layoutSubviews {
[self addSubview:self.headerView];
[self.headerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(@0);
make.top.equalTo(@0);
make.right.equalTo(@0);
make.height.equalTo(@50);
}];
[self.headerView addSubview:self.headerImgV];
[self.headerView addSubview:self.headerLb];
[self.headerImgV mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(@5);
make.top.equalTo(@5);
make.width.equalTo(@40);
make.height.equalTo(@40);
}];
[self.headerLb mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.headerImgV.mas_right).offset(15);
make.top.equalTo(@0);
make.right.equalTo(@0);
make.height.equalTo(@40);
}];
[self addSubview:self.remindInfoLb];
[self.remindInfoLb mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(@0);
make.right.equalTo(@0);
make.height.equalTo(@20);
make.top.equalTo(self.headerView.mas_bottom).offset(0);
}];
[self addSubview:self.closeBtn];
[self.closeBtn mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self);
make.width.equalTo(@40);
make.height.equalTo(@20);
make.bottom.equalTo(@-10);
}];
}
}
这里只是附上了部分代码,思路如下:
1、在layoutSubviews这个方法里面进行布局(不解释)。
2、观察代码可以发现,在对子控件进行布局时,都是先表明了关系(哪个是父视图,哪个是子视图),再进行布局的。这样有一点好处就是,我们再做子控件相对于父控件布局的时候无需再指定是相对于哪个视图进行布局,也就简化了代码。
3、布局的关键在于分清哪些是子控件,哪个是父控件,以上面第一个代码段为例,通过视图的添加关系很容易看出视图的父子关系,而下面的适配代码默认就是相对于父视图布局的,也就是说self.headerView 左和上 的间距就是相对于self的布局。
二、用法
给view添加约束
[view mas_makeConstraints:^(MASConstraintMaker *make) {
}];
将view的所有约束删除,重新添加新约束
[view mas_remakeConstraints:^(MASConstraintMaker *make) {
}];
覆盖view的某些约束
[view mas_updateConstraints:^(MASConstraintMaker *make) {
}
Masonry中使用and 和 with 增强可读性
包装:make.width.mas_equalTo(10); //省去将10 包装为NSNumber的过程。(make.width.equalTo(@10))
如果感觉不出来好处,那么看下面:
make.size.equalTo([NSValue valueWithCGSize:CGSizeMake(100, 100)]); make.size.mas_equalTo(CGSizeMake(100, 100));
简化:
make.right.equalTo(superView).offset(-20)//等于下面
make.right.offset(-20)//默认就是父控件
make.size.multipliedBy(.5);
make.width.height.mas_equalTo(100);//设置多参数
make.left.top.mas_equalTo(100);
make.edges.mas_equalTo(superView)
.insets(UIEdgeInsetMake(x,x,x,x)) //设置内边距
宏的使用:
在Masonry.h 前添加宏 MAS_SHORTHAND 可以避免在约束时写mas_
三、常见Bug
下面的断言说的是布局的空间没有添加到父视图中
*** Assertion failure in -[MASViewConstraint install]
解决方案:当我们在布局一个子控件时,如果用到其他子控件表明位置或者尺寸关系,我们应当确保在布局这个子控件之前已将需要用到的控件都添加到父视图上。
四、Masonry与视图的属性
self.btn1 = [UIButton buttonWithType:UIButtonTypeCustom];
self.btn1.backgroundColor = [UIColor orangeColor];
[self.btn1 addTarget:self action:@selector(pressBtn1) forControlEvents:UIControlEventTouchUpInside];
self.btn2 = [UIButton buttonWithType:UIButtonTypeCustom];
self.btn2.backgroundColor = [UIColor redColor];
[self.view addSubview:self.btn1];
[self.view addSubview:self.btn2];
[self.btn1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.top.equalTo(self.view);
make.height.mas_equalTo(200);
make.right.equalTo(self.btn2.mas_left);
}];
[self.btn2 mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.mas_equalTo(self.view);
make.centerY.height.width.equalTo(self.btn1);
}];
UIButton *changeBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[changeBtn addTarget:self action:@selector(pressChange) forControlEvents:UIControlEventTouchUpInside];
changeBtn.frame = CGRectMake(100, 400, 100, 100);
changeBtn.backgroundColor = [UIColor greenColor];
[self.view addSubview:changeBtn];
UIButton *printBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[printBtn addTarget:self action:@selector(pressPrint) forControlEvents:UIControlEventTouchUpInside];
printBtn.frame = CGRectMake(100, 500, 100, 100);
printBtn.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:printBtn];
- (void)pressChange {
// self.btn1.alpha = 0;
self.btn1.hidden = YES;
}
- (void)pressPrint {
NSLog(@"%@",NSStringFromCGRect(self.btn1.frame));
}
- (void)pressBtn1{
}
当我们点击了绿色按钮,也就是设置了btn1的hidden或者alpha属性使其隐藏
从右侧的视图并未发生变化可以看出,虽然btn1不可见,但是其frame一定没有发生变化,那么点击灰色按钮验证一下咯
{{0, 0}, {207, 200}}
来测试一下更新好不好用咯
- (void)pressChange {
[self.btn1 mas_updateConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.view).offset(50);
}];
}
在开发中经常会遇到使用AutoLayout时控制台输出警告的情况,我们在实际布局中经常做的一件事是一个控制器需要布局几个模块,那么每个模块的视图肯定是要封装的,那么这里面的每一个模块假设都是用Masonry进行适配,然后到控制器里的self.view上面布局,这是一个很合乎情理的事情,但是如果我们不在self.view上面布局,重新定义一个父视图,我们可能首先会想到创建这个父视图时不用给这个父视图frame,因为我们使用Masonry就是避免使用frame,那么运行后 我们会发现各种的约束警告,其实,我们应当给予这个父视图一个高度,如果不确定,我们可以先给一个值