前言: 不知道从何时起,Frame 布局开始渐渐淡出 iOS 开发的舞台,越来越的多的小伙伴开始使用 xib、storyboard、swiftUI 及第三方 SDK 来进行布局。然而,Frame 布局始终是我心目中的 iOS 布局之王。
BY:一位不愿透露姓名的靓仔
iOS 布局的前世今生:
1.原始:Frame
iOS 开发中最古老、最简陋的布局方式,由开发人员手动设置各个视图的原点(origin)及大小(size)从而确定整个视图在父视图的位置。
在最初的 iOS 开发中,由于针对机型有限,适配简单,这种古老的布局方式显得游刃有余。然而在资本主义利益熏心的驱使下,千奇百怪的 iOS 设备不断进入人们的日常生活,程序猿们不得不一一适配这些新设备,渐渐地, Frame 布局显得越来越力不从心,革命的声音就此出现……
2. 抛砖引玉:AutoLayout
在 Apple 赚得盆满钵满之后,终于没忘记体恤一下其生态圈的各位工程师,为我们在 iOS6 中带来了新的局部方案:Autolayout,此套方案核心为“参照”及“约束”,开发人员只需要从这两个角度将视图的呈现方式使用代码描述出来,后续的工作即可交给系统自动处理。
然而理想都是丰满的,现实总是残酷的,AutoLayout 提供的 API 过于冗长,而要将视图的“参照”及“约束”描述清楚,需要从多个维度调用多条 API 才能达到,而且 AutoLayout 的脾气也不太好,一旦缺少必要的”参照“或者”约束“,就可能会导致整个程序挂掉,此时的 Autolayout,更像是一个半成品,没几个程序员愿意为它举牌,大家宁愿继续被 Frame 约束压榨,也不愿意使用 Autolayout ……
3. 曙光:Masonry
Autolayout 无人问津,究其根源是因为其 API 设计问题。但大家都明白,Autolayout 的核心思维正是解决 iOS 布局之痛的关键,此时陆续有第三方开始尝试封装对 Autolayout 进行封装,简化其 API,提高易用性。 Masonry 在众多第三方布局 SDK 中脱颖而出,其简练的语法及函数式调用深得广大开发者的青睐。
古人云:凡是都有其两面性。autolayout 在 masonry 的光环加持下大行其道,成为 iOS 程序员对付 UI 布局问题的一道利剑,然而 autolayout 也有其先天弱势 —— 。
Autolayout 的性能问题:
Autolayout 会将约束条件转换成线性规划问题,在通过 Cassowary 算法求解线性规划问题得到 frame。对 autolayout 底层原理及 Cassowary 算法感兴趣的同学可以自行 google,在这里讲可能篇幅不够。可以简单的理解为 AutoLayout 在界面需要布局的时候会把我们设定好的约束条件转换成 X 个 N 元 N 次方程,然后扔给系统,让系统计算出最终视图上各个元素的 frame,如果你对 N 元 N 次方程的求解复杂度还没有个概念的话,可以尝试自己写一个程序来求解 N 元 N 次方程……
借用 Draveness 大佬的分析图,可以看到 Autolayout 的性能明显低于 Frame 布局,所谓出来混的总要还的,我们在代码上偷的懒,在性能上可一分都没少还(遮脸哭)。我们知道当渲染时间大于1/60秒(16.67毫秒)时,程序即会出现肉眼可察觉的卡顿。上图中,Frame 布局可以保持在500个 View 同时渲染时间低于16毫秒,而使用 autolayout 时,仅仅 100 个 view 的渲染时间就达到了 55.11 毫秒。
回归初心:
我做了7年 iOS 开发,我写了7年 Frame 布局。对我来说,Frame 布局有其独有的魅力与吸引力,我喜欢把视图中每个元素掌握在自己手中的感觉,喜欢在使用 Frame 布局时,每个元素随着代码在我脑海中逐渐拼接成整个视图的感觉。
也许你会认为这是我的偏激与顽固,在实际工作中,我也使用 xib, storyboard,使用 autolayout 和 masonry,学习并汲取其精华将其应用到 Frame 布局中。既然我们可以为 autolayout 封装 SDK 提高其 API 的易用性,那为什么不能封装最原始的 Frame 布局来提高其通用性呢?这样既可以优雅的使用 Frame 布局,又可以得到最佳的新能表现。
现在我使用一套自己不断改进后的 Frame 布局方式,在 API 简洁度、易用性、代码复杂度上我都认为比目前的第三方布局用起来更加得心应手。
让我们使用一个稍微复杂一点的界面看看我现在如何使用 Frame 布局,在屏幕控制器中央显示一个抢购信息,涉及到了多个子视图的布局:
界面一共13个元素,以上布局代码共14行,就目前来说比其他任何一种布局方式更加简短明了,目前这套布局方案在 Frame 的基础上,大量使用了 autolayout 中 ”参照“ 和 ”约束“ 等思维,将核心思路集中在视图与视图的空间关系上,并使用链式调用最大程度减少冗余代码并保持清晰的代码可读性。
由于布局中均使用相对关系,所以无论在任何尺寸手机上或者屏幕改变旋转方向,均可以正常布局。而在上述代码运行完毕之后,所有视图的 frame 信息均已计算完成,系统没有额外的计算负担。