参考资料:
- https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/AutoLayoutConcepts/AutoLayoutConcepts.html
- http://www.objc.io/issues/3-views/advanced-auto-layout-toolbox/,翻译:http://objccn.io/issue-3-5/
- <iOS Auto Layout Demystified 2nd Edition>
- http://blog.csdn.net/colorapp/article/details/38422073,我之前关于Autolayout的博客,讲述Autolayout的基本以及VFL的使用
- http://stackoverflow.com/questions/20609206/setneedslayout-vs-setneedsupdateconstraints-and-layoutifneeded-vs-updateconstra/20927069?stw=2#20927069
- http://stackoverflow.com/questions/20305654/what-is-the-difference-between-all-these-auto-layout-update-methods-are-all-nec
- http://blog.shiqichan.com/UIScrollView-And-Autolayout/
- https://github.com/forkingdog/UITableView-FDTemplateLayoutCell,http://blog.sunnyxx.com/2015/05/17/cell-height-calculation/
spring & struts
就是指使用autosizing masks,它决定了一个view当它的superview的大小发生改变时,这个view会发生什么。具体来说:
the struts:指定了当superview改变大小时,view是否有灵活并且自动修复页边的处理能力。
UIViewAutoresizingFlexibleLeftMargin
UIViewAutoresizingFlexibleRightMargin
UIViewAutoresizingFlexibleTopMargin
UIViewAutoresizingFlexibleBottomMargin
the springs:指定了当superview改变大小时,view的宽和高的变化。
UIViewAutoresizingFlexibleWidth
UIViewAutoresizingFlexibleHeight
布局过程
与使用 springs & struts 相比,Auto Layout在视图被display(绘制)之前添加了两个额外的步骤: updating constraints(更新约束) 以及 laying out views(视图布局)。每一步都是依赖于前一步的操作的,display pass依赖于layout pass,layout pass依赖于updating constraints pass。
第一步: updating constraints pass
可以认为这个过程是测量阶段( “measurement pass”)。这是一个
自底向上的过程(from subview to super view),为后续具体设置view的frame的layout过程准备必要的信息。可以通过调用 setNeedsUpdateConstraints来触发这个过程。尽管任何对约束系统的修改都将会自动触发这个过程。但是,在自定义view中,对于可能影响到layout的改变,通过这个调用来告知Auto Layout是非常有必要的。同时,在自定义view中,在这个阶段内可以通过覆盖 updateConstraints 方法来为这个view添加你需要的约束。
第二步: layout pass
这个是
自顶向下的过程(from super view to subview)。在layout阶段,constraint system才真正开始影响views的布局,在OS X中,会设置view的frame;在iOS中,则是设置view的center和bounds。可以通过调用 setNeedsLayout来触发这个layout过程,但layout过程其实不会立即发生,而是将这个请求记录下来,稍后才会触发,这样的实现方式,就保证了我们不用担心很频繁地调用setNeedsLayout方法,这些调用可能最终会合并成一次layout过程。
可以通过调用 layoutIfNeeded(iOS)/layoutSubtreeIfNeeded(OS X)来让一个view tree立即更新layout过程。如果接下来的操作需要view最新frame之后进行,就可以通过调用这个方法来实现。在自定义view中,可以通过覆盖 layoutSubviews/layout 来对进行灵活地控制整个layout过程。
第三步: display pass
最后一步,display过程将会把views渲染到屏幕上,这个过程跟是否使用Auto Layout是无关的。这是一个自顶向下的过程,可以通过调用 setNeedsDisplay 来触发。setNeedsDisplay会触发一个被延迟的重绘,在这个中间,多次setNeedsDisplay调用最终会被合并为一次重绘。在自定义view中,可以通过覆盖drawRect:来灵活控制display过程。
由于每一步都需要基于之前的一步操作完成之后才能进行。所以,在display过程触发时,如果发现layout有没有被应用的修改,则首先会触发一个layout过程;同样地,layout 过程触发时,如果发现constraints发生了改变,则首先会触发update constraints过程。
需要注意的是,这三个步骤并不是单向的。Constraint-based layout是一个迭代式的过程。layout pass 可以基于之前的layout结果对constraints进行修改,这会再次触发一个constraints的更新过程,之后又会触发一个layout pass。这个特性可以用来为自定义view创建高级的layouts,但是如果自定义view的layoutSubviews方法中每次被调用都会触发另外一个layout pass,这样就会导致一个死循环之中。
在自定义View中使用Auto Layout
在实现自定义View时,我们需要知道下面这些与Auto Layout相关的概念:指定一个合适的intrinsic content size,区分view的frame和alignment rect,实现baseline-aligned layout,如果hook到layout过程。参考官方的文章:
https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/ImplementingView/ImplementingView.html
Intrinsic Content Size
The intrinsic content size is the size a view prefers to have for a specific content it displays. 关于intrinsic content size这个概念,翻译为固有内容尺寸。可以根据你需要展示的内容,来决定是否需要以及为哪个dimensions设置intrinsic content size。这点可以参考我之前的博文:
http://blog.csdn.net/colorapp/article/details/38422073。总之来说,一般情况下,custom view中,这个其实用途不大,主要是用来理解 auto layout。
在UIView的头文件中,对需要设置intrinsic