iOS——Masonry约束内容整理Masonry约束是什么Masonry约束与AutoLayout之间的关系CocoaPods的引入方式Masonry约束的具体内容三个核心方法基本结构与写法点语法用法链式点语法equalTo 与 mas_equalTo 的区别offset方向规律对UIScrollView约束时的特殊处理点语法速查表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然后在需要使用的文件里导入头文件#importMasonry/Masonry.hMasonry约束的具体内容三个核心方法Masonry 提供了三个用来设置约束的方法分别对应不同的使用场景mas_makeConstraints 第一次给视图添加约束时 mas_updateConstraints 更新某已有的约束这样可以保持其他约束不变 mas_remakeConstraints 把旧的约束全部清掉重写该视图的约束实际应用中用得最多的是mas_makeConstraints在视图第一次布局的时候调用。如果需要临时对视图约束进行修改比如按钮点击后视图位置发生变化就可以用mas_updateConstraints只改你需要改的那几条或者用mas_remakeConstraints整体重写。此外调用这三个方法之前视图必须已经被添加到父视图上这也是使用约束的前提条件否则没有对照[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)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)设置这条约束的优先级举几个常见写法// 贴满父视图make.edges.equalTo(self.view);// 四边各内缩 16ptmake.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的链式点语法它支持把多个属性写到一个链上就不用分开写好几行我们以代码演示// 分开写make.top.equalTo(self.view).offset(20);make.left.equalTo(self.view).offset(20);// 链式合并写make.top.left.equalTo(self.view).offset(20);这里的.单纯代表对哪个边约束两种写法完全相同需要注意的是链式写法的offset或mas_equalTo会同时作用于链上所有属性。所以如果几个方向的偏移量不一样就不能合并还是得分开写。equalTo 与 mas_equalTo 的区别这两个方法名字很像但接受的参数类型不一样也代表两种不同的用法// 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 然后把所有视图放在中间层上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 的 bottomcontentView 的高度才能被内容撑开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高度典型用法// B 的顶部紧贴 A 的底部间距 12ptmake.top.equalTo(viewA.mas_bottom).offset(12);