现在的位置: 首页 > 综合 > 正文

OC中的VFL

2018年08月03日 ⁄ 综合 ⁄ 共 4473字 ⁄ 字号 评论关闭

VFL自ios6.0就开始了, 不过由于觉得AutoResizingMask一直是可以解决所见的问题的情况下, 所以一直没有花时间来研究这个东西。

自iphone6.0及iphone6 plus后,觉得再不去研究一下VFL对于代码布局的情况下就会比较麻烦,而且随着后期苹果再发布其它的设备的情况下,学习并会使用VFL已然成为iOS开发者的一个必须会的基本技能。

目前我们在已上线的项目中还没有大规模地使用VFL, 通常是使用宏来取当前设备的高度,宽度,以及系统版本号来分辩各种设备下的界面所需布局。当然后随着iphone6和plus的发布, 这种方式也已经有需要改动的必要了。 

好了, 让我们现在切入正题吧。

首先, 先说一下如何在storyboard中使用VFL。

1. 拖动一个视图在界面中,选中这个视图,然后选择菜单, Editor->Pin, Editor->Align等,下面都是可以用来进行动态布局的。 

如选中width, 就可以设置一个值,条件有3种, >=, ==, <=. 

设置完毕后,会在storyboard中显示这个值,如果这个值为黄色,表示XCode无法根据当前所设置的constraint来动态赋值以完成动态布局, 这样的情况运行代码,会导致出现的布局不是期望的,或者可能出现崩溃无法布局的情况。

这时需要再次研究各个布局条件,看系统是否能动态计算出布局,解决后,黄色的标签会自动变成蓝色,这说明系统已经可以根据已设定的constraint来完成自动计算的过程了。

(有时需要注意的是,可能是storyboard的一个小bug, 当设定了多个constraint后,可能界面的标签还是显示成蓝色,但实际上是可以正常进行布局的情况下,可以点击Editor->Resolve Auto Layout Issues->Update Frames, 或者Update Constraint.)

2. 说明一下,添加限制的位置,通常来说是加在它们两个或多个的父视图,或者说是离它们最接近的父视图,如A是B的你视图,要在它们两个上面添加constaint,则应该加在A上。

3. 代码中使用VFL.这里直接上一段代码,然后再挨着分析:

    NSDictionary *dict1 =
NSDictionaryOfVariableBindings(_leftView,
_rightView, _bottomBtn, _centerLabel);

    NSDictionary *metrics = @{@"preDis":@20.0,
@"tailDis":@20,

                              @"horizonPadding":@40,
@"verticalPadding":@10,

                              @"topPadding":@30,
@"bottomPadding":@40};

    NSString *vfl0 =
@"H:|-preDis-[_leftView]-horizonPadding-[_rightView]";

    NSString *vfl1 =
@"H:[_leftView(==_rightView)]";

    NSString *vfl2 =
@"V:[_leftView(==_rightView)]";

    NSString *vfl3 =
@"H:|-preDis-[_bottomBtn]-tailDis-|";

    NSString *vfl4 =
@"V:|-topPadding-[_leftView]-verticalPadding-[_centerLabel]-verticalPadding-[_bottomBtn]-bottomPadding-|";

    NSString *vfl5 =
@"V:|-topPadding-[_rightView]-verticalPadding-[_centerLabel]-verticalPadding-[_bottomBtn]-bottomPadding-|";

    NSString *vfl6 =
@"H:|-preDis-[_centerLabel]-tailDis-|";

    NSString *vfl7 =
@"H:[_leftView(>=100)]";

    [self.view
addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:vfl0 options:0
metrics:metrics views:dict1]];

    [self.view
addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:vfl1 options:0
metrics:metrics views:dict1]];

    [self.view
addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:vfl2 options:0
metrics:metrics views:dict1]];

    [self.view
addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:vfl3 options:0
metrics:metrics views:dict1]];

    [self.view
addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:vfl4 options:0
metrics:metrics views:dict1]];

    [self.view
addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:vfl5 options:0
metrics:metrics views:dict1]];

    [self.view
addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:vfl6 options:0
metrics:metrics views:dict1]];

    [self.view
addConstraints:[NSLayoutConstraint
constraintsWithVisualFormat:vfl7 options:0
metrics:metrics views:dict1]];

    [self.view
addConstraint:[NSLayoutConstraint
constraintWithItem:_bottomBtn
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual toItem:_bottomBtn
attribute:NSLayoutAttributeWidth
multiplier:1.0 constant:0]];

需要注意的是:

1. 上面的代码中, dict1中放置是的接下来要操作的视图列表,直接使用_变量的方式,不要使用属性,因为属性得到的值可能不是一个变量,而是一个计算结果。

2. 同样在NSString *vfl0中使用的视图变量是使用[_变量]的方式,而不能使用[self.属性]的方式,否则编译会报错。

3. NSDictionary *metrics 定义的相当于是接下来要使用到的宏值,主要是用来进行分隔的值。以便在NSString *vfl0中进行替换使用,宏值不能用[]框选。

4. NSString *vfl1 = @"H:[_leftView(==_rightView)]";

    NSString *vfl2 = @"H:[_leftView(==100)]"; 这两名可以配合使用,表示它们两个的值均为100.

5.     [self.view addConstraint:[NSLayoutConstraint constraintWithItem:_bottomBtn attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:_bottomBtnattribute:NSLayoutAttributeWidth multiplier:1.0 constant:0]];

这个值是用来动态计算的, 表示对象 bottomBtn.height == bottomBtn.Width * 1.0 + 0;    当然这里也可以是两个不同对象的计算,主要是用来表示两个对象的某个属性的某个属性值的相对关系。这种相对关系用 
[addConstraints:]; 会比较难以表现。

6.  注意需要把对应的视图的自动布局给关闭掉,否会设置的VFL可能就无效。   self.centerLabel.translatesAutoresizingMaskIntoConstraints
=
NO;

7. 顺便提一下,所有的视图的宽度由于可以是动态计算,或者通过VFL设置, 所以不必在初始化时使用initWithFrame,而是直接使用init方法。

8. 最后说一下使用得最多的是UILabel的动态布局。

因为UILabel之前使用时,常常会用到根据当前的系统版本来计算UILabel的文字长度,从而进行UILabel的frame设置,以实现UILabel随文字的长度来动态调整。使用VFL的情况下则较为简单。

    self.centerLabel = [[UILabel
alloc] init];

    self.centerLabel.backgroundColor = [UIColor
brownColor];

    self.centerLabel.translatesAutoresizingMaskIntoConstraints =
NO;

    self.centerLabel.text =
@"x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,x测试文字,。)";

    self.centerLabel.numberOfLines = 0;

    self.centerLabel.lineBreakMode =
NSLineBreakByCharWrapping;

    [self.view
addSubview:self.centerLabel];

这里注意两点:

1. 设置numberOfLines为0, 如果不设置的话,在ios7.0中该值默认为1.

2. 如果有断行的情况下,设置lineBreakMode


抱歉!评论已关闭.