相信iOS开发人员, 没人不知道masonry是干什么的, 所以就不粘贴什么 "Masonry是一个轻量级的布局框架 拥有自己的描述语法 采用..." 巴拉巴拉的, 直接开始说一下如果使用, 及一些技巧和方法
Masonry源码
以下将从几个方面说一下如何使用Masonry
- 怎样添加约束才能满足一个View, 及masonry的基本使用
- 如何使用masonry等间隙排布几个View
- 更新约束动画
- ScrolView如何布局
- tableViewCell高度动态变化
1. 怎样添加约束才能满足一个View, 及masonry的基本使用
使用约束布局, 不同于frame, 制定x, y, width, height, 就可以了, 要考虑不同的需求, 要添加什么约束, 如果不熟悉, 很可能会这里多一个约束, 那里少一个约束. 其实如果对于约束这回事理解了, 就很容易想明白到底一个View或者多个View布局的时候, 需要什么约束. 通常布局一个View的时候, 需要4条约束就可以固定住位置, 其实frame不就是4条约束嘛, x代表距左, y代表距上, width代表宽, height代表高, 这样一个view就可以确定位置了.
由于代码利用到了, 首先介绍一个宏定义
#define WS(weakSelf) __weak __typeof(&*self) weakSelf = self;
//解释: __weak 指定一个弱引用指针, __typeof(&*self) self的类型, weakSelf 变量名, = self 赋值
WS(ws);
block内部使用ws, 避免循环引用, 为什么会循环引用, 就不做过多解释了
至于为什么要写成&*self, 其实和直接写self没有什么区别, 见这篇文章weakself的一种写法
我们在页面上添加一个View, 想把他放在, 距上200, 水平方向在屏幕中间, 宽高都为150, 那么要这样添加它的约束
UIView *view1 = [[UIView alloc] init];
view1.backgroundColor = [UIColor redColor];
[self.view addSubview:view1];
[view1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(ws.view).offset(200);
make.centerX.equalTo(ws.view);
make.size.mas_equalTo(CGSizeMake(150, 150));
}];
下面就拿这个简单的布局说一下, 为什么这几个东西就能确定一个View的位置.
先看第一条约束make.top.equalTo(ws.view).offset(200)
, 这个约束代表view1的顶部距离屏幕顶部(ws.view和屏幕一样大)200, 那么也就限定了这这个View的顶部的线, 他现在可以是这样的
或者
how2.png
或者 ...
第二条约束make.centerX.equalTo(ws.view)
, 确定了这个View的竖直中心线的位置, 他现在可以是这样的 , 或者更多的
第三条约束make.size.mas_equalTo(CGSizeMake(150, 150))
, 确定了它的宽高, 貌似他只能是这样了, 再不能变化了, 这样也就完了一个View的约束, 确定了它的位置大小
关于这样的基本布局, 再举一个例子, 这次要用到三个View,
- 一个红色父View, 上左右分别距屏幕50(内边距),
- 红色View里面上面有一个绿色字View, 这个绿色View距上100, 宽度200, 高度200, 在红色View竖直中线
- 红色View里面还有个黄色Label, label顶部距绿色View底部20, 宽度和绿色View一样, 底部和红色View底部距离20
代码如下:
UIView *redView = [[UIView alloc] init];
redView.backgroundColor = [UIColor redColor];
[self.view addSubview:redView];
[redView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(ws.view).offset(64 + 50);
make.left.equalTo(ws.view).offset(50);
make.right.equalTo(ws.view).offset(-50);
}];
UIView *greenView = [[UIView alloc] init];
greenView.backgroundColor = [UIColor greenColor];
[redView addSubview:greenView];
[greenView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(redView).offset(100);
make.size.mas_equalTo(CGSizeMake(200, 200));
make.centerX.equalTo(redView);
}];
UILabel *label = [[UILabel alloc] init];
label.backgroundColor = [UIColor yellowColor];
label.numberOfLines = 0;
label.text = @"三扥黄森老将老将赛疯狂森囧带肯老将赛疯狂森囧带肯赛疯狂森囧带肯交两三";
[redView addSubview:label];
[label mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(greenView.mas_bottom).offset(20);
make.width.mas_equalTo(greenView);
make.centerX.equalTo(greenView);
make.bottom.equalTo(redView).offset(-20);
}];
下面逐条约束介绍, 也会说一下"撑满"的概念
首先红色View的三条约束, 就不一一讲解了, 需要说明的是, 这里红色View只有三条约束, 肯定不能确定位置, 这是因为, 它内部的控件布局决定的, 它内部有两个子控件, 绿色View的位置可以确定下来, 但是label的要有多少文字, 不知道, 也就不知道label有多高, label又要里红色VIew底部20 , 所以暂时红色View的高度, 或者说底部位置还不能定下来.
接着说, 绿色View的约束, 绿色View的位置可以确定
make.top.equalTo(redView).offset(100);
确定了这个View顶部线
make.centerX.equalTo(redView);
确定了这个View的竖直中线
make.size.mas_equalTo(CGSizeMake(200, 200));
确定了这个View的宽度, 至此确定位置
最后, label的约束,
make.top.equalTo(greenView.mas_bottom).offset(20);
确定顶部线
make.centerX.equalTo(greenView);
确定竖直中线
make.width.mas_equalTo(greenView);
确定宽度
注意, 其实至此, 对于label来说, 这些约束就足够了, 看一下, 和之前的View相比, 貌似还缺了写什么, 也不满足通常来说的4条, 观察这个View的目前布局, 目前缺少了高度, 或者说底部约束, 这是因为在宽度确定的情况下, label会自动撑开自己所需的高度.
至此其实还没完成, 如果缺了最后一条约束, 其实就是这种情况, 图中为了显示红色View的位置才给了它一点高度, 实际上是没有的为0,
Paste_Image.png一定要加上make.bottom.equalTo(redView).offset(-20);
, 让黄色label的底部对红色View的底部做一个约束, 把红色View撑开 , 才构成了整个完整的约束. 也补上了redView最开始缺的一条
或者换个子路, 这个不把这条约束放在label里, 单独写一个
[redView mas_updateConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(label).offset(20);
}];
这个的意思就是, 我(红色View)内部的子控件都这么高了, 我也得跟上, 我要比label的底部再多20
至此, masonry的基本使用也就这些, 运用熟练, 就会感觉到这种布局方式相对frame的绝对优势.
其他几方面接下来将会在之后的文章中继续说一下, demo里已经有之后要说的示例代码了, 不熟悉masonry可以下载看一下, 也欢迎提出意见, 交流想法
网友评论
https://github.com/zhenglibao/FlexLib
作为iOS开发,你知道什么时候block会造成循环引用吗?
你的简书看的人也不少,希望不要罔下定论,误导各位