约束(Constraint)在IOS编程中非常重要,这关乎到用户的直接体验问题。
IOS中视图约束有几种方式,常见的是在IB中通过Pin的方式手动添加约束,菜单Editor->Pin->...但是我们往往需要更为灵活的操作,那么就要手动编写代码来实现这些操作。
1:长函数方法
Apple的工程师给我们提供了两种方式,第一种用长函数方法的形式
NSLayoutConstraint(item: <#AnyObject#>, attribute: <#NSLayoutAttribute#>, relatedBy: <#NSLayoutRelation#>, toItem: <#AnyObject?#>, attribute: <#NSLayoutAttribute#>, multiplier: <#CGFloat#>, constant: <#CGFloat#>)
函数很长,但是读起来却一点都不吃力,就好像是一句话那样简单,下面通过实例来说明这个函数的用法。例如我们要实现视图(image)距离左右上下的边距都是20这么一个约束。下面是代码:
1?:这行必须添加,所有需要进行约束操作的视图都必须首先确认不自动布局,这里值得注意的是所有约束必须是视图添加到父级视图之后才能开始
2?:image的左边距=父View的左边距 + multiplier*constrant//multiplier是倍数,constant是常数也就是说,image的左边距=父View的左边距 + 20
3?:image的上边距=父View的上边距 + 20
4?:image的右边距= 父View的右边距-20
5?:image的下边距=父View的下边距-20
6?:在image的父View中添加上这组约束
注意:为什么 4?5?的常数是减20不是和上面一样的加呢?原因是这样的,屏幕的坐标是从左上角开始计算的,屏幕左上角的坐标为(0,0),往右边X坐标越大,往下边Y坐标越大,如果要求image的右边距和父View距离20,我们知道这时候父View的X坐标肯定要比image的X坐标大20,此时要唯一确定其右边距的约束,只能是父View的X坐标减去image的右边的X坐标,下边距同理
长函数约束和IB的连线及其类似,如果不理解请看下图(图中照片是博主老婆,么么哒??)
上述约束行为已经唯一确定了image视图该怎么显示,另外NSLayoutAttribute还有很多其他的属性,比如Center,Width等,用法都类似,虽然都很简单,但是我们发现每个属性约束就是这么一个“复杂”的函数,虽然阅读起来没有难度,但是写起来也确实比较麻烦,很容易出错。所以Apple工程师有爱的发明了另外一种约束的表示方法,就是博主重点提到的VFL方法
2:Visual Format Language(VFL)
当你第一次阅读别人写的VFL表达语句,感觉相当复杂,实在不知所以,宁愿去使用上面说的长函数方法,博主记得当初就是这个感觉,后来当真的理解了这些语句,不得不感叹这些奇葩的Apple工程师简直就是天才。用VFL表述上面长函数例子如下:
首先我们要定义个字典,用"image"来表示我们要约束的视图image,你可以用任意的自字符,当然下面的"[image]"也要用这个字符
"H"表示水平方向,“V”表示竖直方向,也就是说如果要做水平方向的约束必须以“H:”打头,竖直方向以"V:"打头左右的“|”表示父级的左边距和右边距。"-20-"表示距离左边的距离是20,右边的"-20-"表示距离父视图右边的距离为20.中间的"[image]"表示我们需要约束的视图用中括号扩起来,理解这些符号之后就很容易理解“H:|-20-[image]-20-|”这条语句了,假如我们要设定image的Width或者Height怎么办,
Width->“H:|-20-[image(300)]-20-]” Height->"V:|-20-[image(400)]-20-]|",
这里约束了image的宽度为300,高度为400,如果约束最少300,那么在小括号中填写>=300
这里我们要问,左边距和右边距约束了20,又约束了宽度和高度,最后视图会变成什么样子呢?当然了,还有一个优先级的问题没有介绍。我们在IB中可以对约束添加优先级,在VFL中需要在数字的后面添加“@”符号,在@符号后面添加数字优先级,比如说我要求宽度约束Width->“H:|-20-[image(300)]-20-]” 实现的是靠右边20,且宽度300,这条语句该改为“H:|[email protected][image([email protected])][email protected]]|”,这表示了在约束冲突的时候,左边距距离20的约束优先级最小只有100,那么就将左边距的约束忽略掉了。当然这么写可以达到预期宽度20靠右边距20显示的效果,同时为了简化我们可以这么写“H:[image(200)-20-]|”,我们看到左边省略了“|”和后面的内容,也就是说可以直接去掉我们肯定不需要的约束部分。在constraintsWithVisualFormat函数中有NSLayoutFOrmatOptions熟悉,这个可以指定约束的视图左对齐右对齐中对其等对齐方式。metrics也是一个字典,一般设置为nil,但是有时候需要动态约束的时候,可以用的上,比如设置
Width->“H:|-20-[image(width)]-20-]” ,上面有代码设置了var dic0 = ["width",a + b],将dic0传入metrics,这样我们的VFL就会计算知道width的大小另外一个技巧如果设定两个视图宽度或者高度相等,可以这样写"H:[imageA(imageB)]",将视图字典里面的Key直接写到小括号中
多个视图间距的约束也很简单,“H:|-20-[imageA]-20-[imageB]-30-|”,这条语句就不用解释了吧??其他的遗漏的小问题也可以自己推理啦