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:

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

[/crayon]

2.mas_updateConstraints:

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

[/crayon]

3.mas_remakeConstraints:

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

[/crayon]

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((...))),功能是把基本类型包装成对象类型:

[/crayon]

1.创建maker

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

[/crayon]

2.生成约束

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

2.1 设置坐标x

[/crayon]

调用过程:

[/crayon]

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

[/crayon]

2.2 设置坐标y

[/crayon]

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

[/crayon]

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

[/crayon]

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

[/crayon]

2.3 设置x、y的值

[/crayon]

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

[/crayon]

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

[/crayon]

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

[/crayon]

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

2.4 设置size

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

3.安装约束

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

[/crayon]

调用过程如下:

[/crayon]

下面分析一下 install的过程:

[/crayon]

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

[/crayon]

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


结束语

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

参考资料

Masonry

Masonry 源码解析

RAC之masonry源码深度解析

Masonry 源码进阶

学习AutoLayout(VFL)

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

热心留言

电子邮件地址不会被公开。