Masonry
文章目录
- Masonry
-
-
- Masonry是什么
- [Masonry和Auto Layout](#Masonry和Auto Layout)
- 基本用法
- mas_equalTo与equalTo的区别
- 处理UIScrollView
- 总结
-
Masonry是什么
Masonry 是一个轻量级的 iOS/macOS 布局框架,用于简化 Auto Layout(自动布局)的代码编写。它通过链式语法替代了苹果原生的繁琐约束语法,让代码更易读、更简洁。
Masonry和Auto Layout
| 维度 | Auto Layout (原生) | Masonry |
|---|---|---|
| 语法 | 冗长,如 view.leadingAnchor constraintEqualToAnchor:... |
简洁链式,如 make.left.equalTo(...) |
| 代码量 | 多,每个约束都要写 active = YES |
少,block 内一口气写完 |
| 可读性 | 较差,约束分散 | 较好,类似自然语言 |
自动关闭 translates... |
需要手动 NO |
自动处理 |
| 约束更新 | 需先找到约束再改 | mas_updateConstraints 直接更新 |
| 性能 | 原生,无额外开销 | 极薄封装,性能几乎无差别 |
| 依赖 | 无 | 需导入第三方库 |
| 适用场景 | 小项目或不想引入依赖 | 追求开发效率和代码简洁 |
基本用法
添加约束
Masonry 中的约束由 MASConstraintMaker 对象的属性(如 top, left, width, height 等)来构建,并通过链式调用设置参照和偏移。
objectivec
UIView* wzm = [[UIView alloc] init];
wzm.backgroundColor = [UIColor redColor];
[self.view addSubview:wzm];
[wzm mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.equalTo(self.view).offset(100);//左上
make.width.height.equalTo(self.view).offset(100);//宽高
make.bottom.right.equalTo(self.view).offset(100);//右下
}];
看上面的这部分代码,我们没有一个一个将参数设置,而是将一些参数串在一起设置,
更新与重制约束
mas_makeConstraints::添加新约束,会与已有约束叠加(如果同一条约束重复会报错)。
mas_updateConstraints::更新已经存在的约束(比如修改 constant)。
mas_remakeConstraints::移除当前视图的所有 Masonry 约束,然后重新添加新的约束。
多个视图的相对约束
objectivec
UIView *blueView = [[UIView alloc] init];
blueView.backgroundColor = [UIColor blueColor];
[self.view addSubview:blueView];
[blueView mas_makeConstraints:^(MASConstraintMaker *make) {
// 在 redView 下方 20 点,左边对齐 redView
make.top.equalTo(redView.mas_bottom).offset(20);
make.left.equalTo(redView);
make.right.equalTo(redView);
make.height.mas_equalTo(50);
}];
居中
objectivec
[view mas_makeConstraints:^(MASConstraintMaker *make) {
make.center.equalTo(self.view);
make.size.mas_equalTo(CGSizeMake(200, 200));
}];
| 属性 | 说明 |
|---|---|
.top / .bottom |
视图的顶部与底部边线 |
.left / .right |
视图的左边与右边(不推荐用于国际化) |
.leading / .trailing |
视图的首边与尾边,推荐用于支持 RTL 语言 |
.width / .height |
视图的宽与高 |
.centerX / .centerY |
视图的水平与垂直中心轴 |
.center |
同时设置 centerX 与 centerY(组合属性,用于快速居中) |
.edges |
同时设置 top、left、bottom、right(组合属性) |
.size |
同时设置 width 和 height(组合属性) |
.firstBaseline / .lastBaseline |
视图的首行与末行文本基线(仅对 UILabel 等文本控件有效) |
.leadingMargin / .trailingMargin / ... |
对应视图的 layoutMargins 布局边距,用于在边距框内对齐 |
mas_equalTo与equalTo的区别
| 方法 | 参数类型 | 是否需要手动包装 |
|---|---|---|
equalTo |
需要传入 NSNumber 或 MASViewAttribute 对象 |
是(基本类型要包装成对象) |
mas_equalTo |
可以直接传入基本数据类型(int、CGFloat、CGSize、UIEdgeInsets 等) |
否(自动包装) |
// 使用 equalTo(手动包装)
make.width.equalTo(@100);
// 使用 mas_equalTo(自动包装)
make.width.mas_equalTo(100);
mas_equalTo,代码更简洁。但需要注意:当比较对象是另一个视图的属性时,两者用法相同,例如 make.left.equalTo(view.mas_right),这时用 equalTo 就够了。
处理UIScrollView
UIScrollView 本身需要确定它在父视图中的位置和大小(这些约束与其他 UIView 一样)。但是 contentSize 无法直接设置,而是由 UIScrollView 的子视图通过 Auto Layout 自动计算得出,如果像对待普通 UIView 一样,只给 UIScrollView 添加子视图并设置位置约束,contentSize 会不正确(通常是 (0,0)),导致无法滚动。
解决
先在UIScrollView内部添加一个contentView,需要的滚动的内容都放在这个contentView中,通过约束这个contentView来驱动contentSize
objectivec
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIScrollView* s1 = [[UIScrollView alloc] init];
[self.view addSubview:s1];
[s1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.view);
}];
UIView* contentView = [[UIView alloc] init];
[s1 addSubview:contentView];
[contentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(s1);
make.width.equalTo(s1);
}];
UILabel* label1 = [[UILabel alloc] init];
label1.text = @"这是第一行内容";
label1.backgroundColor = [UIColor lightGrayColor];
[contentView addSubview:label1];
UILabel* label2 = [[UILabel alloc] init];
label2.text = @"第二行\n第三行\n第四行\n第五行\n第六行\n第七行\n第八行\n第九行\n第十行\n滚动到底部了";
label2.numberOfLines = 0;
label2.backgroundColor = [UIColor cyanColor];
[contentView addSubview:label2];
[label1 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(contentView).offset(20);
make.left.right.equalTo(contentView).inset(15);
make.height.mas_equalTo(40);
}];
[label2 mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(label1.mas_bottom).offset(10);
make.left.right.equalTo(contentView).offset(15);
make.height.mas_equalTo(1000);
}];
[contentView mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(label2.mas_bottom).offset(20);
}];
}
@end
总结
Masonry 用链式语法让 Auto Layout 告别繁琐,核心就是 mas_makeConstraints 添加约束,mas_updateConstraints 更新,mas_remakeConstraints 重建