前言:SDAutoLayout 在发布之后受到了众多iOS开发者的青睐和支持,不到半年时间内在GitHub上已经获得2000+star,同时被众多公司和个人开发者作为开发首选自动布局库。现在,以SDAutoLayout为例简单介绍一下如何设计一个自动布局库。
所谓自动布局,其实就是将手动布局的计算过程抽象出一套算法,然后利用约束模型收集view的宽高左右等各个维度对应的数据,最后在恰当的时机根据约束计算出view的frame。
了解了这个基本原理之后,我们就可以动手设计一个自动布局库了。在设计自动布局库的过程中,我们主要需要解决以下几个问题:
1.何时进行自动布局相关运算?
2.如何实现自动布局算法?
3.如何设计约束模型管理机制?
4.如何设计一套简洁的连式语法API?(此步非必须项,仅供有兴趣者参考,以SDAutoLayout为例)
5.如何实现自动计算cell高度?
1.何时进行自动布局相关运算?
首先,什么时候进行自动布局相关运算才最合适呢?我们知道,当一个view的frame发生改变或者由于其他情况需要调整子view就会触发layoutSubvies方法,在手动布局时我们经常通过重写这个方法来实现对子view的调整。但是我们要设计自动布局库时,显然不应该强行重写view的layoutSubvies方法,这样就会破坏了开发者对view的自主监听和掌控,因此,layoutSubvies方法执行完毕之后才是我们进行自动布局相关运算的最佳时机。好的,那么究竟如何监控这个“最佳时机”的到来呢?此时我想熟悉OC运行时的同学已经想到了,没错,就是利用OC的黑魔法“Method Swizzling”即可完美解决,代码如下(源码地址 ):
2.如何实现自动布局算法?
当解决了自动布局运算时机的问题之后,我们面临的下一个问题就是如何设计自动布局算法,这也是整个自动布局库最核心的部分。
在讲这个布局算法之前,有必要先说一下我总结出的一个自动布局算法要素:先计算绝对属性,后计算相对属性。
那么,何为“相对属性”?相对属性就是需要参照于其他物体才有意义的属性。比如我们会说“河南在河北的南面”,那么这个“南”就是一个相对属性,有了河北作为参照,这个“南”才是有意义的,如果你只说“河南在南面”,那么这个“南”就是没有意义的。在自动布局中,一个view的x、y、centerX、centerY、left、right等属性就属于这种相对属性。
对比“相对属性”,“绝对属性”就很好理解了,所谓“绝对属性”就是不依赖于参照物改变而改变的属性。比如我会说“iPhone6 是4.7英寸屏幕”,那么这个“4.7英寸”就是绝对属性,他不会因为和其他参照物比较而改变。在自动布局中,一个view的width、height属性就是这种绝对属性。
另外,在针对每个“相对属性”计算过程中,“宽高校验”是非常有必要的,如果宽高是不准确的,那么计算出来的right、bottom、centerX、centerY等属性值也肯定是不准确的。示例代码如下(源码地址):
3.如何设计约束模型管理机制?
然后,我们还要设计一下自动布局约束管理机制,也就是说,每个view的约束该交由谁来管理呢?是view自己?还是view的superView呢?结合刚刚对问题一的分析,既然是父view在调用layoutSubvies方法之后再进行自动布局计算,那么让父view来管理所有子view的约束就再合理不过了。在SDAutoLayout中,每个view都有一个autoLayoutModelsArray数组来管理子view的约束,子view在调用sd_layout方法时候会初始化一个约束模型并添加到其父view的autoLayoutModelsArray数组中,这就是为什么在使用SDAutoLayout过程中要先将子view添加到父view然后再做布局设置的原因了。示例代码如下(源码地址):
4.如何设计一套简洁的连式语法API?
链式语法以其简洁明了的优点受到了众多开发者的推崇,在SDAutoLayout库中,约束模型将各种布局数据设置的操作封装进一个个block中,每次置一个维度的约束时实际上是调用了这个维度对应的block,把相关参数以(参数1,参数2)的形式传递给block进行相关设置,然后block每次把约束模型自身作为返回结果传递下去,这样就可以再次用"."来调用其他维度约束对应的block。示例代码如下(源码地址):
5.如何实现自动计算cell高度?
SDAutoLayout为开发者提供了简洁高效的cell高度自动计算方法,使用者只需调用一行代码“[yourCell setupAutoHeightWithBottomView:bottomView bottomMargin:bottomMargin];”即可轻松实现cell高度自动计。
为了实现此功能,SDAutoLayout库在内部建立一个和你的cell一样的模型,然后把你传递过来的model数据赋值给模型cell,设置完成后调用“[self.modelCell.contentView layoutSubviews]”方法来计算cell的真实高度然后返回给你的tableView,同时还会建立cell高度缓存库以供tableView滚动时直接返回cell高度而不必再次计算,如果有需要,你也可以开启cell的Frame缓存机制,这样就会在你的cell出现的时候直接给cell内部控件设置frame而不必时时计算调整,从而大大增加了滚动流畅度。示例代码如下(源码地址):
好了,今天先简单介绍到这里,后期还会针对以上提到的五点内容进行详细深入的介绍,如有好的意见和建议欢迎到SDAutoLayout的GitHub地址https://github.com/gsdios/SDAutoLayout issue我,Thanks!
SDAutoLayout的GitHub地址:https://github.com/gsdios/SDAutoLayout
SDAutoLayout使用者开发的部分app截图http://www.jianshu.com/p/9bc04d3effb8
自动布局QQ交流群:497140713(1群) 519489682(已满)
自动布局视频教程:
SDAutoLayout 基础版视频教程:http://www.letv.com/ptv/vplay/24038772.html
SDAutoLayout 进阶版视频教程:http://www.letv.com/ptv/vplay/24381390.html
SDAutoLayout 原理简介视频教程:http://www.iqiyi.com/w_19rt0tec4p.html