COSLayout 诞生记

COSLayout 是一个基于有向无环图(DAG)的 iOS 布局库。

它的诞生背景是:接手的项目没有用 Interface Builder,项目中遍地都是手动计算 frame 的代码。我想改进这些代码。

最初,我准备用 Auto Layout 来解决问题。但引入 Auto Layout 的 iOS 6 刚发布不久,app 可能还要继续兼容 iOS 5 较长一段时间。所以暂时不能用 Auto Layout。

在 iOS 5 中,虽然可以用 Autoresizing Masks 处理一些简单的布局,但遇到稍微复杂的布局,它就显得力不从心了。于是,我萌生了一个想法:把 Auto Layout 移植到 iOS 5 中。

经过一番调研,得知 Auto Layout 使用了 Cassowary 来求解约束方程。这意味着如果要实现 Auto Layout 的完整功能,必须使用 Cassowary 或类似的约束求解器。

虽然使用约束求解器可以完整复制 Auto Layout 的功能,但我还是选择了放弃。因为学习和使用它恐怕不是一时半会儿就能完成的事。花太多时间来复制 Auto Layout 不是一件很有价值的事。我想快速寻找一个简单的实现来改进既有代码。

我的目的是改进那些手动计算 frame 的代码。因此,是不是刚好可以用手动计算 frame 来代替约束求解?直觉告诉我这是可行的。

在手动计算 frame 的过程中,一个视图的 frame 通常会依赖其他视图的 frame,并且不存在循环依赖。需要一个数据结构来描述这种依赖关系。而这正是 DAG 所擅长的。

此时,心中已经有个大致雏形:提供一个类似于 Visual Format Language 的接口,内部用 DAG 来维护视图间的依赖关系。当某个视图的 frame 发生变化时,依赖该视图的其他视图的 frame 也会更新,并沿着 DAG 一直传播下去。

COSLayout 便是上述的一个实现。它可以像 Auto Layout 那样用约束来描述布局。例如,如果想创建一个视图,使得它占父视图的上半部分,可以这样写:

UIView *subview = [[UIView alloc] init];
[subview.cosLayout addRule:@"ll = rr = bb = 0, tt = 50%"];
[view addSubview:subview];

COSLayout 的确帮我改进了手动计算 frame 的代码。消除了那些繁琐的算术运算,代码也显得更加直观。

以上就是 COSLayout 的诞生过程。