iOS6开始,苹果推出了autoLayout,当时苹果最新手机是iphone5,此时苹果手机只有两种屏幕,3.5英寸和4.0英寸,两种屏幕的宽是一样的,只有高不同,适配成本不高,由于autoLayout有一定的学习成本,所有直到iphone6和iphone6Plus问世之前,autoLayout的使用是不多的。
传统布局思路中,一个view在什么位置,有多大,直接写清楚它的坐标位置和宽高就可以了。在autoLayout中提供了相对的概念,一个view的位置和大小,是相对于父视图或者同级的兄弟视图的位置决定的,决定它们的东西叫约束(NSLayoutConstraint)。
想用的时候…
习惯了传统布局的程序员在效率上并不会比autolayout慢,但是熟练使用了autoLayout之后,在信息比较多,尺寸动态不定的界面中,应该会更有效率。比如说现在我们的app就没有使用autoLayout,但是并没有觉得效率不高。
这里不包括xib里的使用方式,只说代码的
1.使用原生api为每一个约束创建NSLayoutConstraint
API为:
public convenience init(item view1: AnyObject, attribute attr1: NSLayoutAttribute, relatedBy relation: NSLayoutRelation, toItem view2: AnyObject?, attribute attr2: NSLayoutAttribute, multiplier: CGFloat, constant c: CGFloat)
参数解释:
view1 想要添加约束的视图
attr1 想要添加约束的方向\宽高
relation 与约束值的关系(大于,等于还是小于)
view2 被参照对象
attr2 被参照对象所被参照的方向,如顶部,左边,右边等等
multiplier 传入想要的间距倍数关系
c 传入最终的差值
例如:
let viewOneLeftConstraint = NSLayoutConstraint(item: viewOne, attribute: NSLayoutAttribute.Left, relatedBy: NSLayoutRelation.Equal, toItem: view, attribute: .Left, multiplier: 1.0, constant:40)
意思是viewOne这个视图的左边距离view这个视图的左边40
用这种方法比较累赘,需要为每一个约束生成一个NSLayoutConstraint的实例,一个视图需要好几个约束才能确定,代码量比较大
2.苹果推出的VFL(Visual Format Language)语言,其实就是一种规范。它的出现就是为了减轻API带来的繁琐。
API为:
public class func constraintsWithVisualFormat(format: String, options opts: NSLayoutFormatOptions, metrics: [String : AnyObject]?, views: [String : AnyObject]) -> [NSLayoutConstraint]
参数解释:
format 传入固定格式构成的字符串,用来表达想要添加的约束
opts 对齐方式
metrics 一般传入以间距为KEY的字典,如: @{ @”margin”:@20},KEY要与format参数里所填写的“margin”相同
views 传入约束中提到的View
return 返回约束的数组
例如:
let viewDic = ["viewOne" : viewOne, "viewTwo" : viewTwo, "viewThree" : viewThree]
let viewsHConstraint = NSLayoutConstraint.constraintsWithVisualFormat("H:|-[viewOne]-padding-[viewTwo(viewOne)]-padding-[viewThree(viewTwo)]-|", options: NSLayoutFormatOptions(rawValue:0), metrics: ["padding" : 10], views: viewDic)
意思是viewOne的右边距离viewTwo的左边10个像素,viewTwo的右边距离viewThree的左边10个像素,viewOne的左边距离它的superView20个像素,viewThree的右边距离它的superView20个像素
总结一下这个语法。
功能 表达式
水平方向 H:
垂直方向 V:
Views [view]
SuperView |
关系 >=,==,<=
空间,间隙 -
优先级 @value
这种方法比第一种方法的代码要简洁,但是VFL使用需要一定的成本,而且都是字符串容易出错。
3.三方开源库SnapKit(swift) Masonry(OC)
这两个库是同一拨大神写的,SnapKit用在swift上,支持iOS7.0,Masonry用在oc上,支持iOS6.0,使用是非常相似的。它们提供了一个行云流水的链式语法。这里主要讲一下SnapKit在swift上的使用。
先来说明一个方法
func snp_makeConstraints(file: String = #file, line: UInt = #line, @noescape closure: (make: ConstraintMaker) -> Void) -> Void
这个方法就是我们为视图添加约束的主要方法,对应的还有更新约束snp_updateConstraints,重做约束snp_makeConstraints(会把之前的约束删除,添加新的)
以一个小李子来说明,添加一个view,这个view的每个边都距离它的父视图20像素。
let box = UIView()
superview.addSubview(box)
box.snp_makeConstraints { (make) -> Void in
make.top.equalTo(superview).offset(20)
make.left.equalTo(superview).offset(20)
make.bottom.equalTo(superview).offset(-20)
make.right.equalTo(superview).offset(-20)
}
貌似和用系统提供的并没有减少多少的代码量,简化一下就不一样了
let box = UIView()
superview.addSubview(box)
box.snp_makeConstraints { (make) -> Void in
make.edges.equalTo(superview).inset(UIEdgeInsetsMake(20, 20, 20, 20))
}
SnapKit中的视图属性和使用appleAPI的NSLayoutAttribute的对应关系如下:
ViewAttribute | NSLayoutAttribute |
---|---|
view.snp_left | NSLayoutAttribute.Left |
view.snp_right | NSLayoutAttribute.Right |
view.snp_top | NSLayoutAttribute.Top |
view.snp_bottom | NSLayoutAttribute.Bottom |
view.snp_leading | NSLayoutAttribute.Leading |
view.snp_trailing | NSLayoutAttribute.Trailing |
view.snp_width | NSLayoutAttribute.Width |
view.snp_height | NSLayoutAttribute.Height |
view.snp_centerX | NSLayoutAttribute.CenterX |
view.snp_centerY | NSLayoutAttribute.CenterY |
view.snp_baseline | NSLayoutAttribute.Baseline |
优先级:
例如:
make.left.greaterThanOrEqualTo(label.snp_left).priorityLow()
make.top.equalTo(label.snp_top).priority(600)
SnapKit提供了一些便利的方法来同时创建约束
edges
// make top, left, bottom, right equal view2
make.edges.equalTo(view2);
// make top = superview.top + 5, left = superview.left + 10,
// bottom = superview.bottom - 15, right = superview.right - 20
make.edges.equalTo(superview).inset(UIEdgeInsetsMake(5, 10, 15, 20))
size
// make width and height greater than or equal to titleLabel
make.size.greaterThanOrEqualTo(titleLabel)
// make width = superview.width + 100, height = superview.height - 50
make.size.equalTo(superview).offset(CGSizeMake(100, -50))
center
// make centerX and centerY = button1
make.center.equalTo(button1)
// make centerX = superview.centerX - 5, centerY = superview.centerY + 10
make.center.equalTo(superview).offset(CGPointMake(-5, 10))
还可以使用链式属性来增加代码的可读性
// All edges but the top should equal those of the superview
make.left.right.bottom.equalTo(superview)
make.top.equalTo(otherView)
学会了上面的基本操作,就可以愉快的使用SnapKit了
几种方式的简单示例autoLayoutDemo