本文为WWDC2015的Session 219 "Mysteries of Auto Layout Part2" 视频笔记,其内容主要涉及了约束的生命周期和,Autolayout调试两大内容,学习记录了视频内容重要的知识内容,欢迎一起探讨研究.
资源
内容
The Layout Cycle
为了说明
Layout Cycle
,苹果工程师给出了这样以上这张图,果然一图胜千言.基于整个App的运行循环过程中,布局界面上的视图前,首先会进行约束进行更新和设置,然后将最终的布局信息延时地传递给视图,让视图获取到相关Frame的信息,进行位置的尺寸的确定,然后回到主运行循环,等待约束再发生变化.
Constraints Change
- 约束改变后
Frame
不会马上变化 - 重写
layoutSubviews
要十分当心
让约束发生变化的方式主要由以下三种:
1.使用官方极力推荐的NSLayoutConstraint
的``active和
deactive`两个类方法来激活,或无效指定约束.(抛弃掉add/remove约束的方式吧~原因可见Mysteries of Auto Layout Part1 16:27)
方法代码如下:
[NSLayoutConstraint activateConstraints:]
[NSLayoutConstraint deactivateConstraints:]
// 参数为NSLayoutConstraint对象的数组
2.修改约束等式的常量值,乘数因子或者优先值.接触过Autolayout我们应该都知道给视图设置约束时要满足一个约束等式如下.(就当你知道了,(╯﹏╰)b)
当
Constant
或者Multipler
变化时,创建的约束等式也相应改变,使得Layout
引擎重写计算布局.而对于优先值
Priority
的改变,往往表现在两个视图间同一位置的约束,将根据优先级高的计算布局属性,除此之外还有具有instrinsic Content Size
属性的视图间的contentCompressionResistance
或者contentHug
的竞争.
3.添加或移除视图,视图都没,跟自己相关的约束当然也没有喽.(╮(╯▽╰)╭)
当约束改变后,Layout
引擎就会重新计算新的布局,将布局内容的旧值替换成新值,然后调用父视图的setNeedsLayout
.
而对于setNeedsLayout
的描述,官方文档给出了详细说明.此方法只是对当前约束变化了的视图了标记,只有等到下一个视图更新周期时视图才会真正响应约束的变化而改变Frame
.如果想要让视图快速地响应约束的变化,则需要调用layoutIfNeeded
.
Deferred Layout Pass
约束发生变化后,就进入了延迟的布局信息传递过程.为什么说延时的呢?回想一下,我们操作约束变化时经常通过设置动画时间来放大对应Frame的延时改变.在这个阶段里,视图更新所在视图层次内的所有约束,然后重新赋值Frame
属性.
更新视图的约束,使用setNeedsUpdateConstraints
就表示着该视图的约束需要更新,而具体的更新会在将来某一时刻进行.其调用的时机,苹果工程师给了两个情景:
- 当某约束在所在位置变化太慢时,使用
update
期间将更快的更新约束. - 当视图约束频繁且多余的变化时,调用后只会执行最后一次的更新变化.
响应视图布局约束变化后,就到了对视图位置布局的最终设置,而这个过程则是视图从上到下遍历视图层次,调用layoutSuviews(iOS)/layout(OSX)
,设置具体的内部子视图的Frame
.而重写该方法时,主讲人多次提醒开发者需要十分注意重写方法时内部的操作.
重写layoutSuviews
方法时,其内部的约束是不完整的,具体表现为有的子视图已经完成了布局,而有的子视图正在或者还未进行布局.为了保证方法的正确执行,我们必须调用父类的layoutSuviews
,不能在其内部调用setNeedsUpdateConstraints
(时机太晚了,已经进入了布局阶段),并且不能随意地更改约束,防止与其他视图层次相关的约束的改变.
Interacting Legacy Layout (处理系统遗留的布局)
-
当我们用代码使用Autolayout给视图添加约束时,要时刻留意将
translatesAutoresizingMaskIntoConstraints`设为NO,否则添加完约束后就会出现一下约束警告日志. - 如果想要自己设置内部视图的
Frame
时,重写layoutSuviews
,在此方法里设置,切记不要忘记调用父类方法.
Constraint Creation
关于系统自带API进行约束的创建方式一直以来都被我们诟病,设个约束出要那么大坨代码(差评~)...但如果了解使用VFL创建约束的话还是很优雅的,只是实现的约束有所限制.而现在iOS9提供了新的约束创建方式,让开发者可以更加明了,快速地创建约束.
通过查看
UIView
的头文件,可以看到view
的anchor
属性都定义在一个名为UIViewLayoutConstraintCreation
的UIView
分类中.
// NSLayoutXAxisAnchor 类型表示在X轴上的约束
leadingAnchor
trailingAnchor
leftAnchor
rightAnchor
centerXAnchor
// NSLayoutXAxisAnchor 类型表示在Y轴上的约束
topAnchor
bottomAnchor
centerYAnchor
firstBaselineAnchor
lastBaselineAnchor
// NSLayoutDimension 类型表示尺寸相关的约束
widthAnchor
heightAnchor
初次之外,新的NSLayoutAnchor
类的文件里提供了一系列进行相关视图进行约束设置的方法,这里就不一一介绍,可以Command + R
进行看看.
Constraining Negative Space
这里所提到的关于对多个视图进行等间距或者同时居中的情况下,以前的做法就是创建假的UIView
仅仅为提供约束来达成目的,而现在有了UILayoutGuide
对象其表示着一个可以使用Autolayout的布局矩形区域,可以通过视图的分类方法addLayoutGuide
添加guide
,来充当之前仅仅提供约束的假视图,作用于Autolayout
.具体的话就举一个实现让三个按钮等间距排列,结合代码和图应该能刚好理解点.
//UIButton *saveButton;
//UIButton *cancelButton;
//UIButton *clearButton;
UILayoutGuide *space1 = [[UILayoutGuide alloc]init];
[saveButton addLayoutGuide:space1];
UILayoutGuide *space2 = [[UILayoutGuide alloc]init];
[cancelButton addLayoutGuide:space2];
NSLayoutConstraint *spaceConstraint = [space1.widthAnchor constraintEqualToAnchor:space2.widthAnchor];
NSLayoutConstraint *constraintOne = [saveButton.rightAnchor constraintEqualToAnchor: space1.leftAnchor];
NSLayoutConstraint *constraintTow = [cancelButton.leftAnchor constraintEqualToAnchor:space1.rightAnchor];
NSLayoutConstraint *constraintThree = [cancelButton.rightAnchor constraintEqualToAnchor:space2.leftAnchor];
NSLayoutConstraint *constraintFour = [clearButton.leftAnchor constraintEqualToAnchor:space2.rightAnchor];
[NSLayoutConstraint activateConstraints:@[spaceConstraint, constraintOne, constraintTow, constraintThree, constraintFour]];
Unsatisfiable Constraints
想要了解Unsatisfiable
的具体的相关约束以及关联对象,就必须要理解输出的约束警告日志.
现在允许给约束或者视图添加约束标识符
identifier
字符串属性,将会在日志输出中显示,极大让日志内容更加清晰,让开发者快速找到存在问题的约束和视图.
Resolving Ambiguity
出现Ambigous Layout 警告时表示着约束间存在冲突,而造成约束冲突的原因主要有:
- 约束太少
- 约束的优先级冲突
总结
本视频从约束布局的生命周期到如何Debug布局问题,对Autolayout引擎的工作流程
做了充分了说明和Demo演示,也告诉了我们一些在使用Autolayout中值得注意的地方,对工作中使用和处理Autolayout问题有很大的帮助,作为唯一有字幕(当然是英文的😔)的介绍Autolayout的WWDC Session是值得一看.如果还有说明问题,欢迎留言,一起探讨.