基础篇
VFL (Visual format language) 格式字符介绍
注:不明白的没关系,后面用到时候会介绍。
主要API
1 2 3 4 |
|
API参数介绍:
format: 这个参数就是 VFL 语句,如:V:|-20-[label]
;
opts: 枚举参数,默认为0,具体跟据你所实现的需求去选择你想要的枚举;
metrics: 一个字典,里面的key对应的是你在format
中设置的。比如这句:V:|-20-[label(==heigth)]
,表示label
的高度为heigth
,那么这个参数去哪里找呢?就是这个字典里面相应的key对应的值。
views: 这是传所有你在 VFL 语句中使用到的View
。
API使用示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
说明:
解释一下上面使用的 VFL 语句:
第一句H:|-margin-[label(==200)]
H:
代表水平方向
|
代表父视图(superview)
-
表示间隔(后面会详细讲解)
margin
是label
与父视图左边的间距,也就是@{@"margin":@60}
这个字典中margin
对应的值60
[label]
表示此约束是针对label
的
(==200)
表示label
的宽度为200 pts
整句话的意思就是给label
添加 x
坐标为60,宽度为200 pts 的约束条件;
第二句V:|-50-[label(==heigth)]
V:
表示垂直方向
|
代表父视图(superview)
-
表示间隔
50
代表label
与父视图的顶部的间隔为50
(==heigth)
表示label
的高度为height
(@{@”heigth”:@40}字典中对应的40 pts)
完整的描述为,给label
添加y
坐标为50,高度为40的约束条件。
还需要说明的一点是 API 中的 views 是一个字典,这个字典中传入的是你在这个约束条件中用到的所有的 view。如上列中对 label 进行布局,所以这个 views 就是 label。
运行结果如下所示:
通过上面这个例子你应该掌握至少以下几点:
- 使用
H:
和V:
的区别和作用 - 如何设置宽度和高度
metrics
字典的使用
卖个关子:将上面的H:|-margin-[label(==200)]
改为H:|-[label(==200)]
,V:|-50-[label(==heigth)]
改为V:|-[label(==heigth)]
再在 iOS 7 和 iOS 8 模拟器上面运行项目看看结果。然后,再去掉第一句的H:
看看,你肯定会有所发现。继续阅读本文,你都会找到所有的答案。
进阶篇
上面只是简单的介绍了下主要API的基本使用,对于初学者来说,难点应该在于如何书写 VFL 语句。但是,还有一点是更重要的,这一点就是你要能够领悟到,怎样添加约束条件才能将一个 UI 控件布局到你想要的位置。对于这一点,多练习,就会很快掌握的。
下面,我将利用图(一图胜前言啊)文的形式来为你剖析 AutoLayout 的 VFL 语句的含义,进一步让你熟知这种语法。
第一句:H:|-[view]-|
理想中的效果应该是这样的,如下图:
我先解释下这句 VFL 语句的含义,给view
添加离父视图左右边缘各20 pts
的距离。此时,可能有读者会问了,哪里来的 20 pts
?在此说明一下,在使用H:
水平方向时,子视图相对于父视图的间距如果不明确给出的话(明确给出是这样的,比如H:|-30-[view]-|
,这个30 pts
就是左边距),-
代表的就是20 pts
。请注意,我说的是水平方向相对于父视图。
你是否还记得我前面卖的那个关子呢?现在你应该明白了,相对于父视图时,使用 V:
和H:
时,-
所代表的值各为多少了,并且你应该注意到在 iOS 7 跟 iOS 8 之间的区别了。
再解释下上面为什么说是理想中,如果你编写了代码,并实际运行了项目,不用我说你也会发现问题的所在。问题在于,这个约束加上后,你根本就看不到view
在哪。那么,你再把这个view
换成UILabel
或者UIButton
并且给他们的title
属性赋值再看看效果。
你又发现了“新大陆”,这里需要提一个新的东西intrinsicContentSize
,也就是控件的内容尺寸。控件的内容尺寸是根据内容所定的,再看看你写的label
和button
他们的高度是不是就是标题文字的高度呢?如果你把上面的H:|-[view]-|
改为H:|-[view]
用到你的代码中,你更能够领会intrinsicContentSize
这个属性的含义。控件的内容尺寸可以通过UIView
的intrinsicContentSize
属性来获取的,也可以通过invalidateIntrinsicContentSize
方法来在下次UI
规划事件中重新计算intrinsicContentSize
。直接创建一个原始的UIView对象,显然它的内容尺寸为0。
好了,掌握了这句,如果我需要一个全屏的view
,我该怎么写呢?答案是:H:|[view]|
、V:|[view]|
。
第二句:H:|-[view]-|
和V:|-15-[view(==30)]
效果如下图:
我想到这里,不用我解释,大家也明白了。我只说下这两句 VFL 语句的含义,第一句上面说过多的就不再讲了,第二句的意思是,给view
添加距离父视图顶部15 pts
的距离,并且设置view
的高度为30 pts
的约束条件。
第三句:H:|-[view1]-[view2]-[view3(>=50)]-|
前面的都是单个的控件,这次一下给3个控件添加约束条件。解析如下图:
由图我们就可以理解了上面的 VFL 语句的含义了。需要指出的是[view1]-[view2]-[view3]
之间的-
所代表的值并非前面提到的20 pts
,而是8 pts
。前面也提到了,20 pts
是相对于父控件,而同级控件之间的-
表示8 pts
。还有一点是>=50
,我们知道使用H:
时,设置的尺寸是宽度,这里并不是==50
而是>=50
,也就是说view3
的最小宽度为50。
第四句:H:|-[view2(view1)]
和V:[view1]-[view2(view1)]
这里主要想展示一下怎么设置两个控件等宽等高。解析如图:
当然,如果你不想view1
跟view2
之间有8 pts
的间距,你可以这样写V:[view1][view2(view1)]
。
好了,先写到这里吧。
后记
不知道看到这里,你是否有收获呢?掌握了 VFL 语句的基本语法,那么纯代码实现自动布局也是很简单的。后面若是有时间,我会继续更新内容,欢迎大家继续关注。
前面还有一点没有解释,就是 VFL 语句省略H:
也不写V:
的情况。这个其实很简单,不写的话,就代表水平方向H:
。
另外,纯代码书写 AutoLayout 还有一个重要的 API ,如下:
1 2 3 4 5 6 7 |
|
本文暂不介绍,网上已有很多教程是介绍此 API 用法的,读者可以网上查查。需要注意的一点是,在使用上面的 API 时,参数需要满足这样的一个条件:view1.attr1 = view2.attr2 * multiplier + constant
。