今年WWDC苹果官方除了把整个生态系统做了一次全面升级之外,伴随而来还有同期发布的Swift 3.0 . 如果一年前你还犹豫是否把项目核心语言切换Swift有所忌惮的话,也许稍后Swift 3.0正式版的发布会渐渐打消你在这方面的顾虑. 随着近两年Swift迅猛的发展,而在它开源之后,得意与开源社区源源不断的贡献更是如井喷一样的势头. 当然除了iOS平台,Swift同时还支持了Linux. Swift语言给我更直观的感受是,终于不用在写出类似Object-C冗长的代码风格,调用简洁且易读的Swift让人感到很清爽. 我对语言本身其实没有太大的期望,不过如果能有类似 C# 之类的语言的异步风格函数(Async-Style Function)的话,那就再好不过了. 当然从官方放出的Swift路线图可以看出,3.0版本大的革新内容并不多,主要的方向还是剔除掉C语言的影响为主. 如果说Swift在3.0之前还存在生产力的问题(缺少成熟的第三方框架),有时间看看github相关资源,也许现在就是切入的好时机.
提到AutoLayout,我在使用OC语言开发时一直经常使用的是Masonry框架,在慢慢切入Swift之后,虽然其语言特性能够支持OC的混编,但依然让人觉得很麻烦. Masonry使用开发者众多,而其原作者也在众多开发者要求支持Swift版本呼声中推出了SnapKit. 和Masonry一样,SnapKit是一套轻量级的布局框架,同样适用链式语法封装Apple的自动布局约束. 项目发布至今大约一年多的时间,已经在github上有六千多个Star,当然了,这其中也少不了利用Masonry影响力给他打的那些广告。
如果你还记得StoryBoard中那些约束的线条,那么你也一定记得其中 Constriants 的写法。而SnapKit所做的就是这样一件事——让你采用链式语法封装的方式写 Constraints:
当然如果使用过Masonry上面没什么大惊小怪的,但SnapKit比Masonry更为灵活(具体细节后面详细说明):
安装
在安装前需要注意SnapKit要求的环境配置:
[iOS 7.0+ / OS X 10.9+] / [Swift 2.0] / [Xcode 7.0+]
采用Carthage安装SnapKit:
github "SnapKit/SnapKit" >= 0.21.1
安装时指向当前发布的最新版本.通过carthage update 命令生成引用,在项目根目录下找到生成的:
Carthage -> Build -> iOS -> SnapKit.framework
文件,然后把文件集成到:
Project -> General -> Embedded Binaries
选项中,在项目代码中引入:
import SnapKit
编译成功,则安装完成. 当然如果你更习惯CocoaPod或者更多的安装方法请参见官方文档.
基础用法
因为SnapKit设计思路延续了OC版本的Masonry, 只不过换了一种实现语言Swift, 如果你对Masonry非常熟悉,那么其二者基本用法上大同小异.
先看一个基本示例,我们在UI布局中首先尝试布局一个GrayBox:
基本写法跟Masonry没有多磨大的区别, 但在SnapKit中,如果多个属性值一致,可以串连视图属性,增加其可读性,类似上面写法有一个更简单的实现方式:
在SnapKit通过 ‘snp_makeConstraints' 给元素增加约束,约束主要分为边距、宽、高、左上右下距离、基准线, 当然增加约束同样也是可以修正的, 修正方式有位移修正 [‘inset、offset’] 和倍率修正 [multipliedBy].
SnapKit支持的属性与 NSLayoutAttrubute 对照表如下:
其中leading与left、trailing与right 在正常情况下是等价的, 但是当一些布局是从右至左时(比如阿拉伯文) 则会对调. 换句话说大部分情况二者其实是等价的.
修正约束语法一般就是三种,跟Masonry完全一致.
.equalTo:等于
.lessThanOrEqualTo:小于等于
.greaterThanOrEqualTo:大于等于
关于基本用法,官方文档和示例中非常详细这里就不多介绍. 重点说一下其其他Masonry少见的用法.
倍率修正
在布局我们有两个正方形色块,现在采用倍率修正方式,采用倍率修正方式吧橙色视图缩小为灰色视图的一半,如下图:
可以采用multipliedBy实现:
注意这里不得不说是这个multipliedBy方法, 当前只是需要橙色视图大小也就是Size属性,而该方法能够接受的值我们能从其定义中找到,有如下几种值的类型:
同理DividedBy也是如此.
约束引用
在日常布局中,我们可能在多个地方更新同一个约束的值. 这就需要对现有定义的约束能够修改、移除、替代等操作. 而SnapKit可以将约束的结果赋值给一个局部变量或一个类属性,然后对这个约束的引用进行操作. 这样就大大简化我们操作一个约束的成本,同时保证其灵活性.
在页面我们有一个橙色的视图,距离顶部100,横向位置居中. 点击页面Button时移除掉该约束,效果如下:
实现很简单:
首先什么一个约束对象topConstraint, 在对橙色视图添加约束时,引用SuperView顶部间距的约束. 当点击Button移除约束按钮时则触发移除操作:
在触发移除时,通过调用topConstraint的uninstall方法则完成操作. 移除完成后如果更新改约束,例如把橙色视图到顶部距离由原来100改为现在200像素. 直接采用updateOffset(200)即可,当然这个操作之前因为使用uninstall,所以导致约束不可用,在调用updateOffset方法前需要把通过activate将其激活,要不然没有任何效果.
约束优先级
当同一个元素有多个建立多个约束时,可以定义约束的优先级。这样当约束出现冲突的时候,优先级高的约束覆盖优先级低的约束.
SnapKit中元素默认优先级是500(最大数值是1000),也就是priorityMedium()中等级别.除此之外还可以设置如下几个优先级:
priorityLow():设置低优先级,优先级为250
priorityMedium():设置中优先级,优先级为500(默认优先级)
priorityHigh():设置高优先级,优先级为750
priority():可以设置任意的优先级,接受的参数是0-1000的数字.
优先级使用语法是一般放在约束链的结束处,例如:
make.width.height.equalTo(100 *self.view.width).priorityLow()
篇幅所限关于用法参见官方的Demo或者本篇演示的github上源代码. 这里就不做过多赘述.
小结
SnapKit和Masonry一出同源,在设计思想极为相似,但在用法上原作者坐了一些创新,使SnapKit更为灵活适应更多的场景. 虽然SnapKit很好用,但我想很多纯代码进行界面的人应该都知道,它的弊端是非常的耗时且细节琐碎繁多, 极大自主带来的是生产力的不足. 我想很多人跟我一样都有同感. 所以我最近开始尝试是否可以xib/storyboard+SnapKit混合使用,主要布局使用xib/storyboard,在需要动态更新布局的时候使用SnapKit. 效率是提升了一些,但遇到很多特别棘手的问题. xib/storyboard在界面开发上的确可以大大提升开发效率,在部分界面设计场景也的确需要手写代码的灵活性. 如果有更好方案不放可以探讨一下.