Autolayout Guide

autolayout

接触Autolayout的概念已经许久,但都不曾用一下,试想了下,如果用AutoLayout来做Cell布局,是不是就可以不用自己计算高度,省下一大笔代码。用Swift写了段代码,发现还是蛮简单的,只是这中间过程的好多新的概念要了解下。

放下之前的布局观念

旧的模式我们称作springs and struts,在使用时,定义好Frame,也就是坐标和大小,然后它就按照所要求的显示在那里。如果你有2个长文本Label,要先根据文字计算好高度,然后指定第2个Label的Frame Point。

但AutoLayout除了传统的Frame之外,还加了一种相对布局的概念,有点像HTML。

XCode Tools

关于XCode中如何使用AutoLayout介绍,见:http://www.cnblogs.com/YungMing/p/3733491.html

红线代表所写的布局规则不完整或有错误,蓝线则是正确。

Preferred Width & Explicit

  • 第一个是对齐
  • 第二个是添加新的规则
  • 第三个是清除规则
  • 第四个?

选中2个控件时,点右下第一可以看到有这些操作。

选择两个view时可设置

  • 左边对齐,
  • 右边对齐,
  • 顶部对齐,
  • 底部对齐,
  • -
  • x轴中心对齐,
  • y轴中心对齐,
  • 文本底标线对齐,

单选择一个view时可设置

  • 对于父view的x轴中心对齐,
  • 对于父view的y轴中心对齐,

选择框

  • 添加完约束后不进行任何操作,
  • 在添加约束后重新摆放约束涉及到的view,
  • 在添加约束后重新摆放所有这个容器内的view

上面的十字是”与最近的邻居的约束”, 填上数字, 单击虚线变成实线就是要添加这个约束.

这里的”邻居”是将一个包含子view的父view看做一个装了一堆积木的盒子, 积木相对于盒子的边框和其他的积木都作为”邻居”

定义的宽高数据约束

  • 宽度指定,
  • 高度指定,

定义多个view之间的宽高约束

  • 宽度相同,
  • 高度相同,

列表, 多个view之间的对齐约束, 等同于前一菜单的内容
(列表, frame更新方式, 等同于前一菜单)
(确定按钮, 设置约束后点击添加)

(上半部分菜单的操作对象是当前选中的view, 下半部分的操作对象是选中view内的view)

刷新frame(使用当前已经设置的所有约束),

刷新约束(根据当前的约束和frame, 更新约束的constant值),

添加缺失的约束(自动添加系统认为你应该添加却忘记添加的约束, 测试中经常搞出冲突)

重置为系统建议的约束(清理系统认为重复/冲突的约束, 测试中经常搞出问题)

清理所有约束(删除对象上绑定的所有约束)

(在添加约束的时候, 刷新哪些视图)

同级view和父view

子view

问题: 约束和约束之间会冲突, 无论是xib和xib, xib和代码, 代码和代码. 约束的冲突一般在特定情况下才会报, 比如竖屏没问题但是横屏出现冲突, 也可能xib拖错上来就冲突之类. 约束冲突系统自动会解决, 通常依靠的是权级, 但是由于一般情况使用无法确定某一约束应该处于什么权级, 所以很难设置正确的权级以应对冲突. 约束的冲突, 在系统自动解决时可能相同情况出现不同的处理, 导致某些不能每次都重现的问题. 约束冲突, debug连调时会出现错误log, 可以根据log查找解决冲突. 约束冲突, 在ios6上未见crash, 在ios7上偶发crash. xib和代码的取舍: autolayout现在已经不是”用不用”的问题, 而是”怎么用”的问题, 底层框架貌似已经完全删除了autoresizemask, 而是自动将autoresizemask转换为auto layout 也就是说, 这种情况下可以使用原来的autoresizemask, 但是系统还是将他们拿来当autolayout使的, 使用过程中自动转换的constraint同样会遭遇冲突, 冲突导致的问题更加诡异而不好处理
现在我经常碰到的就是, 比如一个控件, 它和它的父view之间使用的autolayout是用代码指定的, 我可以确定constraint的形式, 但是在实现它的时候为了方便使用了xib处理其内部的view, xib上拖放constraint由于比较复杂而我尚未明晰, 会在某些特定的情况下出现constraint冲突, 系统自动处理冲突时会将权级较低的constraint放弃, 而由于无法明确每一条constraint应该处于什么权级, 经常会出现偶发问题(如竖屏情况下constraint之间没有问题, 横屏过来之后就发现某个控件内的某个label上不小心没有删除指定宽度的constraint, 导致变形的控件和控件内label的constraint冲突, 然后引发一系列的连锁反应)

当然, 使用xib定义viewcontroller同样要接触到constraint, 而且每一个都需要管理和指定(默认constraint经常会导致冲突)

规则介绍

Space Constraint

  • .Top
  • .Trailing
  • .Buttom
  • .Leading

Constraint to Margin

Width & Height Constraint

  • Width
  • Height

.Leading.Margin

VFL(Visual Format Language) 语法

1
NSString *vfl = @"V:|-5-[_view]-10-[_imageView(20)]-10-[_backBtn]-5-|";

http://www.cocoachina.com/industry/20131108/7322.html

手工 Constraint

NSLayoutConstraint

1
2
3
4
5
6
7
[self.view addConstraint: [NSLayoutConstraint constraintWithItem:blueView
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:redView
attribute:NSLayoutAttributeLeft
multiplier:1
constant:0]];

REF::