AutoLayout之纯代码布局

AutoLayout之纯代码布局

基础篇

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

AutoLayout之纯代码布局_第1张图片

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


主要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
4
5
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)

-表示间隔(后面会详细讲解)

marginlabel与父视图左边的间距,也就是@{@"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。

运行结果如下所示:

AutoLayout之纯代码布局_第2张图片

通过上面这个例子你应该掌握至少以下几点:

  • 使用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]-|

理想中的效果应该是这样的,如下图:

AutoLayout之纯代码布局_第3张图片

我先解释下这句 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,也就是控件的内容尺寸。控件的内容尺寸是根据内容所定的,再看看你写的labelbutton他们的高度是不是就是标题文字的高度呢?如果你把上面的H:|-[view]-|改为H:|-[view]用到你的代码中,你更能够领会intrinsicContentSize这个属性的含义。控件的内容尺寸可以通过UIViewintrinsicContentSize属性来获取的,也可以通过invalidateIntrinsicContentSize方法来在下次UI规划事件中重新计算intrinsicContentSize。直接创建一个原始的UIView对象,显然它的内容尺寸为0。

好了,掌握了这句,如果我需要一个全屏的view,我该怎么写呢?答案是:H:|[view]| 、V:|[view]|


第二句:H:|-[view]-|V:|-15-[view(==30)]

效果如下图:

AutoLayout之纯代码布局_第4张图片

我想到这里,不用我解释,大家也明白了。我只说下这两句 VFL 语句的含义,第一句上面说过多的就不再讲了,第二句的意思是,给view添加距离父视图顶部15 pts的距离,并且设置view的高度为30 pts的约束条件。


第三句:H:|-[view1]-[view2]-[view3(>=50)]-|

前面的都是单个的控件,这次一下给3个控件添加约束条件。解析如下图:

AutoLayout之纯代码布局_第5张图片

由图我们就可以理解了上面的 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)]

这里主要想展示一下怎么设置两个控件等宽等高。解析如图:

AutoLayout之纯代码布局_第6张图片

当然,如果你不想view1view2之间有8 pts的间距,你可以这样写V:[view1][view2(view1)]

好了,先写到这里吧。


后记

不知道看到这里,你是否有收获呢?掌握了 VFL 语句的基本语法,那么纯代码实现自动布局也是很简单的。后面若是有时间,我会继续更新内容,欢迎大家继续关注。

前面还有一点没有解释,就是 VFL 语句省略H:也不写V:的情况。这个其实很简单,不写的话,就代表水平方向H:

另外,纯代码书写 AutoLayout 还有一个重要的 API ,如下:

1
2
3
4
5
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

本文为转载文章    

你可能感兴趣的:(iOS)