关于布局(UIViewHierarchy)
1. layoutSubviews
在iOS 6之前版本,此方法的缺省实现不会做任何事情(实现为空),iOS 6开始,此方法的缺省实现是使用你设置在此View上面的constraints(Autolayout)去决定subviews的position和size。 UIView的子类如果需要对其subviews进行更精确的布局,则可以重写此方法。只有在autoresizing和constraint-based behaviors of subviews不能提供我们想要的布局结果的时候,我们才应该重写此方法。可以在此方法中直接设置subviews的frame。 我们不应该直接调用此方法,而应当用下面两个方法。
2. setNeedsLayout
此方法会将view当前的layout设置为无效的,并在下一个update cycle里去触发layout更新。
3. layoutIfNeeded
使用此方法强制立即进行layout,从当前view开始,此方法会遍历整个view层次(包括superviews)请求layout。因此,调用此方法会强制整个view层次布局。
总结
UIView的setNeedsDisplay和setNeedsLayout方法。首先两个方法都是异步执行的。而setNeedsDisplay会自动调用drawRect方法,这样可以拿到UIGraphicsGetCurrentContext,就可以画画了。而setNeedsLayout会默认调用layoutSubviews,就可以处理子视图中的一些数据。
综上所诉,setNeedsDisplay方便绘图,而layoutSubViews方便处理数据。
关于约束(UIConstraintBasedLayoutCoreMethods)
@interface UIView (UIConstraintBasedLayoutCoreMethods)
- (void)updateConstraintsIfNeeded NS_AVAILABLE_IOS(6_0);
- (void)updateConstraints NS_AVAILABLE_IOS(6_0);
- (BOOL)needsUpdateConstraints NS_AVAILABLE_IOS(6_0);
- (void)setNeedsUpdateConstraints NS_AVAILABLE_IOS(6_0);
@end
1. setNeedsUpdateConstraints
当一个自定义的view某一个属性的改变可能影响到界面布局,我们应该调用这个方法来告诉布局系统在未来某个时刻需要更新。系统会调用updateConstraints去更新布局。
2. needsUpdateConstraints
constraint-based layout system布局系统使用这个返回值来确定是否调用updateConstraints
3. updateConstraintsIfNeeded
我们可以调用这个方法触发updateContraints的操作。在needsUpdateContraints返回YES时,才能成功触发updateContraints的操作。立即触发约束更新,自动更新布局。
4. updateContraints
自定义view应该重写此方法在其中建立constraints.注意:要在实现在最后调用[super updateContraints]
Auto Layout Process 自动布局过程
与使用springs and struts(autoresizingMask)比较,Auto layout在view显示之前,多引入了两个步骤:updating constraints 和laying out views。每一个步骤都依赖于上一个。display依赖layout,而layout依赖updating constraints。 updating constraints->layout->display
第一步:updating constraints,被称为测量阶段,其从下向上(from subview to super view),为下一步layout准备信息。可以通过调用方法setNeedUpdateConstraints去触发此步。constraints的改变也会自动的触发此步。但是,当你自定义view的时候,如果一些改变可能会影响到布局的时候,通常需要自己去通知Auto layout,updateConstraintsIfNeeded。
自定义view的话,通常可以重写updateConstraints方法,在其中可以添加view需要的局部的contraints。
第二步:layout,其从上向下(from super view to subview),此步主要应用上一步的信息去设置view的center和bounds。可以通过调用setNeedsLayout去触发此步骤,此方法不会立即应用layout。如果想要系统立即的更新layout,可以调用layoutIfNeeded。另外,自定义view可以重写方法layoutSubViews来在layout的工程中得到更多的定制化效果。
第三步:display,此步时把view渲染到屏幕上,它与你是否使用Auto layout无关,其操作是从上向下(from super view to subview),通过调用setNeedsDisplay触发,
因为每一步都依赖前一步,因此一个display可能会触发layout,当有任何layout没有被处理的时候,同理,layout可能会触发updating constraints,当constraint system更新改变的时候。
需要注意的是,这三步不是单向的,constraint-based layout是一个迭代的过程,layout过程中,可能去改变constraints,有一次触发updating constraints,进行一轮layout过程。
注意:constraints(updateConstraints)-> layout Subviews(layoutSubViews)-> display(drawRect) 这三步不是单向的,如果layout的过程中改变了constrait, 就会触发update constraints,进行新的一轮迭代。我们在实际代码中,应该避免在此造成死循环。