iOS——Masonry约束内容整理

iOS------Masonry约束内容整理

Masonry约束是什么

  • 对于iOS开发来说,视图的位置和大小怎么确定,作为初学者我们一开始接触到的是使用frame直接写死一个视图的坐标和大小,但直接写死带来的后果就是视图之间变得过于死板,一个窗口发生变化,为了匹配对应的变化,往往要改很多个视图的坐标和大小

  • 所以我们接触到了 Auto Layout 这套机制来做这件事,但原生的写法十分繁琐,详情可以查看我的这篇文章【iOS】 AutoLayout初步学习 ,设置一个约束就要写一大串 NSLayoutConstraint,代码可读性很差,效率也不够高

  • Masonry 解决了这个问题。它是对 Auto Layout 的一层封装,将又长又难读的代码,变成了简洁的点语法链式调用, 其实层还是在帮你生成 NSLayoutConstraint,只是写起来十分简洁

Masonry约束与AutoLayout之间的关系

  • Masonry 并不是抛弃了 Auto Layout的机制,而是完全对 Auto Layout 的封装。你用 Masonry 写的每一条约束,最终都会被翻译成系统的 NSLayoutConstraint 对象添加到视图上

  • 除此之外,Masonry 还会自动把 translatesAutoresizingMaskIntoConstraints 设置为 NO,在正常的AutoLayout中需要手动关闭,但这里它会自动帮我们做这件事

CocoaPods的引入方式

Masonry 通过 CocoaPods 安装(这里不多赘述),在 Podfile 里加一行就行:

复制代码
pod 'Masonry'

然后在需要使用的文件里导入头文件:

objc 复制代码
#import <Masonry/Masonry.h>

Masonry约束的具体内容

三个核心方法

Masonry 提供了三个用来设置约束的方法,分别对应不同的使用场景:

复制代码
mas_makeConstraints      第一次给视图添加约束时
mas_updateConstraints    更新某已有的约束,这样可以保持其他约束不变
mas_remakeConstraints    把旧的约束全部清掉,重写该视图的约束
  • 实际应用中用得最多的是 mas_makeConstraints,在视图第一次布局的时候调用。
  • 如果需要临时对视图约束进行修改,比如按钮点击后视图位置发生变化,就可以用 mas_updateConstraints 只改你需要改的那几条,或者用 mas_remakeConstraints 整体重写。

此外,调用这三个方法之前,视图必须已经被添加到父视图上,这也是使用约束的前提条件,否则没有对照

objc 复制代码
[self.view addSubview:redView]; // 先加进去

[redView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.top.equalTo(self.view).offset(100);//这里的约束稍后会介绍
    make.left.equalTo(self.view).offset(20);
    make.width.mas_equalTo(200);
    make.height.mas_equalTo(50);
}];

基本结构与写法

Masonry 约束的基本结构长这样:make代表视图本身,先约束哪条边(top),再说等于谁(self.view),最后加上偏移量(100)

objc 复制代码
make.top.equalTo(self.view).offset(100);
// 解读:这个视图的 top,等于 self.view 的 top,再往下偏移 100pt

点语法用法

Masonry 的点语法是它最直观的地方,常用的属性和方法整理如下:

点语法 / 方法 说明
.top .bottom .left .right 对应视图的上下左右四条边
.leading .trailing 首边和尾边,推荐用这个替代 left/right,支持阿拉伯语等 RTL 布局
.width .height 宽和高
.centerX .centerY 水平和垂直居中轴
.center 同时设置 centerX 和 centerY
.edges 同时设置 top + left + bottom + right
.size 同时设置 width 和 height
.equalTo(view) 等于某个视图或 mas_ 属性,传的是对象
.mas_equalTo(value) 等于某个具体数值,传的是基本类型或结构体
.offset(CGFloat) 在约束基础上偏移,正负决定方向
.insets(UIEdgeInsets) 配合 .edges 做四边内缩
.multipliedBy(CGFloat) 乘以系数,常用于按比例设宽高
.priority(MASLayoutPriority) 设置这条约束的优先级

举几个常见写法:

objc 复制代码
// 贴满父视图
make.edges.equalTo(self.view);

// 四边各内缩 16pt
make.edges.equalTo(self.view).insets(UIEdgeInsetsMake(16, 16, 16, 16));

// 宽度是父视图的一半
make.width.equalTo(self.view).multipliedBy(0.5);

// 水平居中 + 固定宽高
make.centerX.equalTo(self.view);
make.width.height.mas_equalTo(100);

链式点语法

  • 可能你注意到了这里的写法可以在make后面连续用.连接好几个边,这就是Masonry的链式点语法,它支持把多个属性写到一个链上就不用分开写好几行,我们以代码演示:
objc 复制代码
// 分开写
make.top.equalTo(self.view).offset(20);
make.left.equalTo(self.view).offset(20);

// 链式合并写
make.top.left.equalTo(self.view).offset(20);
  • 这里的.单纯代表对哪个边约束,两种写法完全相同

需要注意的是,链式写法的 offsetmas_equalTo 会同时作用于链上所有属性。所以如果几个方向的偏移量不一样,就不能合并,还是得分开写。

equalTo 与 mas_equalTo 的区别

这两个方法名字很像,但接受的参数类型不一样,也代表两种不同的用法

objc 复制代码
// equalTo:接视图对象或 mas_ 属性,  因为有对比,所以是针对其他视图的偏移
make.width.equalTo(otherView);          // 宽度和 otherView 相同
make.top.equalTo(viewA.mas_bottom);     // top 等于 viewA 的 bottom

// mas_equalTo:接基本数据类型或结构体, 用于写死高度,大小等等
make.width.mas_equalTo(100);
make.size.mas_equalTo(CGSizeMake(100, 50));
make.edges.mas_equalTo(UIEdgeInsetsMake(10, 10, 10, 10));

记忆方式很简单:带 mas_ 前缀的就是接数字或结构体,没有前缀的就是接视图。

offset方向规律

offset 的方向和坐标轴是一致的,但对于不同的边,正负产生的效果会不一样:

属性 正值效果 负值效果
.top.offset(n) 向下移动(远离顶部) 向上移动
.bottom.offset(n) 向下撑出(超出父视图) 向上收缩(常用 -16
.left.offset(n) 向右移动(远离左边) 向左移动
.right.offset(n) 向右撑出 向左收缩(常用 -16
  • 只需要记住,offset的正数是向下或者向右, 负数与正数相反,类似于frame的坐标即可

对UIScrollView约束时的特殊处理

  • ScrollView 是 Masonry 里最容易出问题的地方,原因在于 ScrollView 有一个 contentSize(内容区域的大小),它和 ScrollView 本身的 frame 是两回事。

  • 直接把子视图约束到 ScrollView 上,系统搞不清楚 contentSize 是多少,结果就是 ScrollView 没法滚动。

  • 所以我们需要加一个中间层 contentView, 然后把所有视图放在中间层上

objc 复制代码
UIScrollView *scrollView = [[UIScrollView alloc] init];
UIView *contentView = [[UIView alloc] init];

[self.view addSubview:scrollView];
[scrollView addSubview:contentView];

// scrollView 张开贴满屏幕
[scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(self.view);
}];

// contentView 的 edges 等于 scrollView,撑开 contentSize
// 同时锁定宽度等于 scrollView,这样只能纵向滚动,也可以锁定高度,这样就能横向滚动
[contentView mas_makeConstraints:^(MASConstraintMaker *make) {
    make.edges.equalTo(scrollView);
    make.width.equalTo(scrollView);
}];

// 最后一个子视图的 bottom 必须连到 contentView,系统才能知道contentView到底多高
//因为添加进入的视图有高度,而contentView并没有约束高度,所以你需要在这里对bottom相对的约束一下让系统可以根据视图的高度计算出contentView的大小
[lastSubview mas_makeConstraints:^(MASConstraintMaker *make) {
    make.bottom.equalTo(contentView).offset(-20);
}];
  • 逻辑是这样的:contentView 的 edges 贴着 scrollView,这样 contentView 的大小就决定了 scrollView 的 contentSize;宽度锁死等于 scrollView 的宽,就只允许纵向滚动;最后一个子视图的 bottom 连到 contentView 的 bottom,contentView 的高度才能被内容撑开,scrollView 才能真正滚动起来

点语法速查表

常用的 mas_ 属性:当你在 equalTo() 里需要对齐另一个视图的某条边时,需要用 mas_ 前缀属性来取到那条边。

mas_ 属性 说明
view.mas_top 上边
view.mas_bottom 下边
view.mas_left 左边
view.mas_right 右边
view.mas_centerX 水平中线
view.mas_centerY 垂直中线
view.mas_width 宽度
view.mas_height 高度

典型用法:

objc 复制代码
// B 的顶部紧贴 A 的底部,间距 12pt
make.top.equalTo(viewA.mas_bottom).offset(12);
相关推荐
pop_xiaoli1 小时前
【iOS】类和分类的加载
macos·ios·objective-c·cocoa
Hesionberger1 小时前
LeetCode72.编辑距离(多维动态规划)
java·开发语言·c++·python·算法
流年似水~1 小时前
iOS 开发进阶之路:从能跑到能维护
人工智能·程序人生·ios·语言模型
国科安芯1 小时前
空间辐射环境下抗辐射 MCU 可靠性机理及航空安全应用研究综述
单片机·嵌入式硬件·macos·无人机·cocos2d·risc-v
Via_Neo1 小时前
Bash Game
开发语言·bash
2301_780943842 小时前
第四阶段:实践与深化
学习
zdr尽职尽责2 小时前
Untiy 处理Aseprite 资产 解决偏移问题
学习·unity·c#·游戏引擎
菜菜的顾清寒2 小时前
C++面试题自用-持续更新
开发语言·c++
t***5442 小时前
如何在 Dev-C++ 中使用 Clang 调试
开发语言·c++