Masonry1.0.2 源码解析

在了解Masonry框架之前,有必要先了解一下自动布局的概念。在iOS6之前,UI布局的方式是通过frame属性和Autoresizing来完成的,而在iOS6之后,苹果公司推出了AutoLayout的布局方式,它是一种基于约束性的、描述性的布局系统,尤其是苹果的手机屏幕尺寸变多之后,AutoLayout的应用也越来越广泛。

但是,手写AutoLayout布局代码是十分繁琐的工作(不熟悉的话,可以找资料体验一下,保证让你爽到想哭,^_^);鉴于此,苹果又开发了VFL的布局方式,虽然简化了许多,但是依然需要手写很多代码;如果,你希望不要手写代码,那么可以用xib来布局UI,可以图形化添加约束,只是xib的方式不太适合多人协作开发。综合以上的各种问题,Masonry出现了,这是一款轻量级的布局框架,采用闭包、链式编程的技术,通过封装系统的NSLayoutConstraints,最大程度地简化了UI布局工作。

本文主要分析一下Masonry的源码结构、布局方式和实现原理等等。

框架结构

Masonry框架的源码其实并不复杂,利用自己的描述语言,采用优雅的链式语法,使得自动布局方法简洁明了,并且同时支持iOSMacOS两个系统。Masonry框架的核心就是MASConstraintMaker类,它是一个工厂类,根据约束的类型会创建不同的约束对象;单个约束会创建MASViewConstraint对象,而多个约束则会创建MAXCompositeConstraint对象,然后再把约束统一添加到视图上面。

图1

布局方式

Masonry的布局方式比较灵活,有mas_makeConstraints(创建布局)、mas_updateConstraints(更新布局)、mas_remakeConstraints(重新创建布局)三种:

1.mas_makeConstraints:

给视图(视图本身或父视图)添加新的约束

2.mas_updateConstraints:

更新视图的约束,从视图中查找相同的约束,如果找到,就更新,会设置makerupdateExistingYES

3.mas_remakeConstraints:

给视图添加约束,如果视图之前已经添加了约束,则会删除之前的约束,会设置makerremoveExistingYES

Masonry的布局相对关系也有三种:.equalTo(==)、.lessThanOrEqualTo(<=)、.greaterThanOrEqualTo(>=)。

Masonry的布局关系的参数也有三种:

1. @100 –> 表示指定具体值

2. view –> 表示参考视图的相同约束属性,如view1的left参考view2的left等

3. view.mas_left –> 表示参考视图的特定约束属性,如view1的left参考view2的right等

实现原理

Masonry是利用闭包和链式编程的技术实现简化操作的,所以需要对闭包和链式编程有一定的基础。下面会根据案例来具体分析一下Masonry的实现细节,代码实现的功能是设置view1frameCGRectMake(100, 100, 100, 100);其中,mas_equalTo(...)是宏,会被替换成equalTo(MASBoxValue((...))),功能是把基本类型包装成对象类型:

1.创建maker

首先调用mas_makeConstraints:,这是一个UIView的分类方法,参数是一个设置约束的block,会把调用视图作为参数创业一个maker

2.生成约束

接下来,开始利用maker产生约束,即调用block(constraintMaker)

2.1 设置坐标x

调用过程:

其中,上述代码根据maker保存的view和传入的约束属性layoutAttribute创建了一个MASViewAttribute对象,然后根据viewAttribute对象创建了一个MASViewConstraint约束对象,代码如下:

2.2 设置坐标y

由于make.left返回的是MASViewConstraint对象,所以调用的top应该是MASViewConstraint类中的方法(该方法继承自父类MASConstraint),调用过程如下:

如果一个maker添加多个约束后,就会创建MASCompositeConstraint对象,创建约束集合的过程如下:

在创建了MASCompositeConstraint对象后,就会更新maker中的约束数组,在最后添加约束的时候,就会是全部的约束对象,代码如下:

2.3 设置x、y的值

make.left.top返回的对象是MASCompositeConstraint类型,调用过程如下:

下面分析一下设置第二个属性secondViewAttribute的过程,因为Masonry重写了setter方法,过程如下:

由于@100NSNumber类型,所以执行self.offset来设置偏移量,代码如下:

这里有网友疑惑,因为self.layoutConstraint在上面的方法中一直是nil,设置它的constant属性是没有意义的,不知道这么写有何意义?其实,我也有同样的疑问!!!

2.4 设置size

另外,make.size的实现过程和上面的分析类似,有兴趣的可以自行参考,看一看具体的实现过程,在此不做分析。

3.安装约束

下面分析一下约束的安装过程

调用过程如下:

下面分析一下install的过程:

求两个视图的最小父视图的代码如下:

其实,上述代码是先判断firstsecond的视图是否一样,如果一样,直接返回;如果不一样,就判断fisrt的父视图和second是否一样,如果一样,就返回;不一样,继续判断first的父视图和second的父视图是否一样,如果一样,就返回;不一样,重复迭代。


结束语

Masonry的源码分析完结,如果文中有不足之处,希望指出,互相学习。

参考资料

Masonry

Masonry 源码解析

RAC之masonry源码深度解析

Masonry 源码进阶

学习AutoLayout(VFL)

iOS开发-自动布局篇:史上最牛的自动布局教学!

感觉不错,打个赏?
微信                                 支付宝
pay_weixin            pay_zhifubao
金额随意 快来“”我呀~
联系方式:kelvin@fishbay.cn

发表评论

电子邮件地址不会被公开。 必填项已用*标注