您的位置:首页 > 编程语言

AutoLayout之纯代码布局

2014-12-13 10:04 127 查看


AutoLayout之纯代码布局

基础篇


VFL (Visual format language) 格式字符介绍



注:不明白的没关系,后面用到时候会介绍。


主要API

1
2
3
4

+ (NSArray *)constraintsWithVisualFormat:(NSString *)format
options:(NSLayoutFormatOptions)opts
metrics:(NSDictionary *)metrics
views:(NSDictionary *)views;

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
45
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

UILabel *label = [[UILabel alloc] init];
label.backgroundColor = [UIColor lightGrayColor];
label.textColor = [UIColor whiteColor];
label.text = @"纯代码自动布局";
/* 要实现自动布局,必须把该属性设置为NO */
label.translatesAutoresizingMaskIntoConstraints = NO;
/* 添加约束条件前一定要先将控件添加到superView上 */
[self.view addSubview:label];
/* 水平方向约束条件 */
NSArray *constraints1 = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-margin-[label(==200)]"
options:0
metrics:@{@"margin":@60}
views:NSDictionaryOfVariableBindings(label)];
/* 垂直方向约束条件 */
NSArray *constraints2 = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-50-[label(==heigth)]"
options:0
metrics:@{@"heigth":@40}
views:NSDictionaryOfVariableBindings(label)];
[self.view addConstraints:constraints1];
[self.view addConstraints:constraints2];

说明:

解释一下上面使用的 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
45
6
7

+(instancetype)constraintWithItem:(id)view1
attribute:(NSLayoutAttribute)attr1
relatedBy:(NSLayoutRelation)relation
toItem:(id)view2
attribute:(NSLayoutAttribute)attr2
multiplier:(CGFloat)multiplier
constant:(CGFloat)c;

本文暂不介绍,网上已有很多教程是介绍此 API 用法的,读者可以网上查查。需要注意的一点是,在使用上面的 API 时,参数需要满足这样的一个条件:
view1.attr1
= view2.attr2 * multiplier + constant

本文为转载文章    
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: