[关闭]
@khan-lau 2014-10-08T15:00:21.000000Z 字数 6395 阅读 2083

Autolayout及VFL经验分享

编程 iOS


Autolayout,开始于iOS6.0

一.什么时候用autolayout比较适合

1.不负责任的骑墙派说法:apple的设备越来越多了,你的应用应该都使用al。(并且用sb)

2.要看应用内容决定。如果你的内容是信息众多,同时需要展示的类别也很多,尺寸动态不定,甚至这些是在列表中的。(如社交应用)。Al能给于很大的帮助。

3.Mac os的应用。现在都做iOS了。mac app的窗口,会有大小变化。al比较合适。

4.支持多向转屏的iPad应用。(有需要支持多方向iphone场景么?那么长,脑残了?)

5.其他业务不复杂,页面较少的应用,其实,cocoa程序员写了多年code都有自己的ui编程习惯,这些习惯对于他们来说是很高效的。就算是第一项所说,布局的坐标都是相对的。

如果是习惯于code写布局的,建议可以继续沿用,同时也要学习al。自我感觉al和传统布局写法,工作量不会相差太多。但是VFL用熟练了以后会有很大的改善。

二.autolayout的基础理论

al的核心出发点是

1.view具有自我计算尺寸,布局的能力。通过它自身的内容,能够得到尺寸。

2.view的布局位置,确定于它与superview及其他view的关系。

3.与传统的autoresizingmask自适应相比,al更精确,能绝对的确定view的布局。

4.view不一定需要一个初始的rect。al中,view如果有足够的constraint,便可以确定自己的尺寸和位置,并且知道自己和其他view的关系。即,想确定view的布局,就给它(们)添加constraint。

三.xib下的autolayout

似乎al和xib布局模式生来就是要搞在一起的。用xib加al,view布局非常简单容易。编程工作立刻变成了美工的连线拼图游戏。

开启xib或者sb后,选择需要view(s)。选择menu的Editor,选择Pin。子菜单的项目就是可用的constraints。
Xcode Menu 'Pin'

菜单: 代表的意义
Width 固定自身宽度
Height 固定自身宽度
Horizontal Spacing 固定两个view的水平间距
Vertical Spacing 固定两个view的垂直间距
Leading sapce to Superview view相对于Superview左边的间距
Trailing space to Superview view相对于Superview右边的间距
Top space to Superview view相对于Superview顶部的间距
Bottom space to Superview view相对于Superview底部的间距
Widths Equally 两个view保持等宽
Heights Equally 两个view保持等高

xib界面右下角工具条也有可以编辑constraint的方式:
Xcode Menu 'Pin'

每个constraint添加后都是可以编辑的。选中某个constraint后开启右边栏选inspector。可以修改数值。(这个数值是view间的偏移量)和优先级。

自己慢慢拖着玩去。这不是傻瓜教程。点到位,自己研究。

xib下的al比较直观。可以基本看到效果和误差值。还有不正确的constraint的提示。少了constraint编译器会补,多了会提示报错。(不过都会引起界面布局不对,自己慢慢调吧,哥现在还是满篇alert,没有让编译器感觉矛盾费解的constraint,都是可以work的。)

还有resolve的方式解决constraint的问题,抱歉,我不会。

四.编码方式使用autolayout

对于页面不多,的普通应用。xib/sb加al。拖拖拽拽。娱乐中就可以完成UI的工作。al的确给于了不少方便。

不过多年的强迫症程序猿怎么会忍受这种很逊的方式。(拖积木?不敲代码?好像一天没做事。)

1.Visual format language (应该不算语言)

Apple的工程师很有爱,发明了这种哭笑不得的象形文字。感觉它就是种解析方式。

Apple的官方文档给出了少之又少的文档和坑爹的例子。(视频我没看,不知道怎么样)网上的同学们也写了点不痛不痒的几句代码。你这是学了1+1就让人搞微积分的节奏么?要写不写清楚,不如不写。

从厚道的老外那看了几篇。自己体会了些,分享给大家。只是个基本水平吧,会了这些,代码写al应该没有问题了。深入的我也还不会,希望遇到更有爱的牛人分享。

VFL在程序中由支持:

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

2.VFL例子

写vfl字串的时候,脑海里要想象出画面的合理性。不合理的constraint会导致程序运行时报错或者直接崩溃。

随便写几个

  1. NSDictionary *dict1 = NSDictionaryOfVariableBindings(_boxV,_headerL,_imageV,_backBtn,_doneBtn);
  2. NSDictionary *metrics = @{@"hPadding":@5,@"vPadding":@5,@"imageEdge":@150.0};
  3. NSString *vfl = @"|-hPadding-[_boxV]-hPadding-|";
  4. NSString *vfl0 = @"V:|-25-[_boxV]";
  5. NSString *vfl3 = @"V:|-vPadding-[_headerL]-vPadding-[_imageV(imageEdge)]-vPadding-[_backBtn]-vPadding-|";

dict1就是api 中需要的最后一个参数views。由上述宏来完成。
metrics定义了一些VFL中要用的参数。

下面有些VFL字串,一看便知如何使用metrics。
看到:

1)|表示superview.

  1. |-间距-[view1对象名]-(>=20)-[view2对象名]

不写H/V就表示横向,间距可以写固定值也可写>/<。 形象化的理解,|是用来确定view上、下、左、右关系的。
想要确定从上到下的关系,就加V:|。那么这个vfl字串就可以描述从上到下的view们的关系。

2)看到vfl3里面,[](方括号)表示view,()(圆括号)表示尺寸数值。支持大小等于。或者另一个view |-[view1(view2)],v1的宽度等于v2。

3)优先级表示。如V:|-50@750-[view(55)],或者写到metrics(类似于html div 的 z轴)里面更好。 具体定义查看UILayoutPriority。有几个固定的数值。1000表示必须支持。

4)options,这个要看具体需要。如果是竖排V布局,可以添加NSLayoutFormatAlignAllLeft,让他们对齐。
根据需要也可以添加按位或NSLayoutFormatAlignAllLeft | NSLayoutFormatAlignAllRight。(鬼知道什么需要,自己看经验吧)

5)写好以后一般把constraint添加给superview:

  1. NSString *vfl1 = @"|-hPadding-[_headerL]-hPadding-|";
  2. [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:vfl1 options:0 metrics:metrics views:dict1]];

6)还有一个api用于生成单个constaint

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

对于参数,记得,view1.attr1 = view2.attr2 * multiplier + constant就好。
这个是不用VFL的,好理解,但是不方便。如果用这个写。工作两不会比传统布局少多少。

五,实际操作中的问题

上面都是理论,世界操作会有些奇怪的问题要注意。这节才是重点。 xib模式,没啥要注意的,xib里报warning就报吧,我也不知道怎么弄,一切正常就好。 编码模式中,

1.addConstraint(s)前,view应该去部被addSubView上去了。

2.不必给views写frame

3.给必要的view关掉AutoresizeingMask。[_aView setTranslatesAutoresizingMaskIntoConstraints:NO];

4.UILabel换行要写linebreakMode,要写numberOfLines(iOS7.0默认好像是1,坑爹了)

5.UILabel要想换行,一定要添加preferredMaxLayoutWidth。否则没法初始化宽度。

编码模式感受到的最大方便。label换行不用写行高计算了。完全自动适应。label所在的superview也会自动计算rect。这才是al的精华。

所以,可以不用写这些了:

  1. /*
  2. if([[UIDevice currentDevice].systemVersion floatValue]<7.0){
  3. CGSize titleS = [title sizeWithFont:[_headerL font]
  4. constrainedToSize:CGSizeMake(270.0, CGFLOAT_MAX)
  5. lineBreakMode:NSLineBreakByWordWrapping];
  6. _headerL.frame = CGRectMake(_headerL.frame.origin.x,
  7. _headerL.frame.origin.y,
  8. _headerL.frame.size.width, titleS.height);
  9. } else {
  10. CGRect titleR = [title boundingRectWithSize:CGSizeMake(270.0, CGFLOAT_MAX)
  11. options:NSStringDrawingUsesLineFragmentOrigin
  12. attributes:nil
  13. context:nil];
  14. headerL.frame = CGRectMake(_headerL.frame.origin.x,
  15. _headerL.frame.origin.y,
  16. _headerL.frame.size.width, titleR.size.height);
  17. }
  18. */

我遇到了些问题,至今没有解决:

纯代码写的Viewcontroller 无法正常显示al布局。用空白的xib做了vc后,其余再用code写,就正常了。怀疑自己写的self.view,还需要针对autolayout做什么处理。

至此,al,基本功能已经可以为你服务了。的确方便很多,建议还是使用VFL代码模式,熟练后能够提高很多效率。

  1. - (void)setupViewConstraints
  2. {
  3. NSDictionary *views = @{@"scrollView": self.scrollViewProxy,
  4. @"autoCompletionView": self.autoCompletionView,
  5. @"typingIndicatorView": self.typingIndicatorView,
  6. @"textInputbar": self.textInputbar,
  7. };
  8. [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView(==0@750)][autoCompletionView(0)][typingIndicatorView(0)]-0@999-[textInputbar(>=0)]|" options:0 metrics:nil views:views]];
  9. [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:0 metrics:nil views:views]];
  10. [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[autoCompletionView]|" options:0 metrics:nil views:views]];
  11. [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[typingIndicatorView]|" options:0 metrics:nil views:views]];
  12. [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[textInputbar]|" options:0 metrics:nil views:views]];
  13. NSArray *bottomConstraints = [self.view constraintsForAttribute:NSLayoutAttributeBottom];
  14. NSArray *heightConstraints = [self.view constraintsForAttribute:NSLayoutAttributeHeight];
  15. self.scrollViewHC = heightConstraints[0];
  16. self.autoCompletionViewHC = heightConstraints[1];
  17. self.typingIndicatorViewHC = heightConstraints[2];
  18. self.textInputbarHC = heightConstraints[3];
  19. self.keyboardHC = bottomConstraints[0];
  20. self.textInputbarHC.constant = [self minimumInputbarHeight];
  21. self.scrollViewHC.constant = [self appropriateScrollViewHeight];
  22. if (self.isEditing) {
  23. self.textInputbarHC.constant += kAccessoryViewHeight;
  24. }
  25. }

本来来源: http://blog.csdn.net/mozixiong/article/details/14165391

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注