AutoLayout---理论

转自:https://github.com/NemoAir/AutoLayoutFlowDemo


viewcontroller中和 “约束-布局-渲染” 过程有关的主要方法和流程。

1. -initWithNibName 
  如果使用 StoryBoard 加载 ViewController ,则会直接调用 -initWithCoder 方法,而不会调用该方法。
  而通过加载 Xib 或者直接 -init 都会调用这个方法
2. -loadView
3. -viewDidLoad
  这里需要注意,在 iOS8 中,Xib文件中的view在这个阶段并不会加载到self.view的层次结构中。所以这
  个时候如果进行布局或者约束的生成和改变是无效的,而 iOS7  这个时候已经将 Xib 里的 view 加到 self.view 的层次结构中
4. -viewWillAppear
5. -viewWillLayoutSubviews 
    这个方法会使self.view 调用layoutSubviews
6. [self.view layoutSubviews]
    调用了这个方法后,就会对 self.view 的 subviews 也调用 
    -updateConstraint
    方法,更新约束。在iOS8中,这个时候Xib中加载的view已经加入到self.view的层次结构中
8. [self updateConstranits];  
9. -viewDidLayoutSubviews
10. -viewDidAppear
11. -viewWillDisappear
12. -viewDidDisappear
13. -dealloc

首先自动布局发生的顺序是:

1.更新约束。
2.依赖约束系统计算出subviews的frame开始布局。
3.根据计算出的frame重新在屏幕上渲染。

在第2步的过程中可能重复触发第一步的约束更新操作,也就是在发生布局的时候可能还会触发更新约束的过程,高级的约束可能会出现这种情况,同时这种情况要注意不要形成死循环。 所以不能在第一步的约束更新操作中配置布局,例如调用

[self.view layoutIfNeeded]

来触发布局,这样可能会造成死循环。

约束和布局的几个相关方法介绍

约束和布局的几个相关方法

1) [self.view setNeedsUpdateConstraints]
2) [self.view updateConstraintsIfNeeded]
3) [self.view setNeedsLayout]
4) [self.view layoutIfNeeded]
5)  [self.view setNeedsDisplay] 

5)

 [self.view setNeedsDisplay] 这个方法和渲染有关,但是因为名字比较相似,我自己也混淆过,所以也一起说明下

1)

 [self.view setNeedsUpdateConstraints] 告诉约束系统view约束系统需要更新

2)

 [self.view updateConstraintsIfNeeded]  立即更新view的约束

这两个方法都是针对约束的操作方法。 1)调用后告诉系统该view上的约束有更新,系统相当于有一个需要更新该view的标记flag,在下次 进行计算或更新约束的时候.比如调用了2)就会调用viewcontrollerde

  -updateViewConstraints

但是这里有个坑需要注意。如果单独调用2)不一定会触发updateViewConstraints。 因为 1)和 2)的实现类似下面布局更新方法的实现原理:

-(void)layoutIfNeeded {
  if (self._needsLayout) {
      UIView *sv = self.superview;
      if (sv._needsLayout) {
         [sv layoutIfNeeded];
      } else {
         [self layoutSubviews];
      }
  }
}

所以在更新约束的时候要 1)、 2)一起调用才能保证约束立刻被计算。 而且在任何地方对约束进行改变都会触发 1)的方法。 1)会调用2),2)又会触发 viewController的-updateViewConstraints方法,所以最后还可以在updateViewConstraints方法中最后配置一 次布局约束。但是我经过考虑,在需要触发约束改变的地方就直接改变约束会比较好。-updateViewConstraints 方法作为最后一步来补 救约束的选择。 同时约束的计算是从subview到superview的,这点和布局、渲染到屏幕的过程刚好相反。布局和渲染是从superview到subview中来进行的。

3)

[self.view setNeedsLayout] 标记view布局需要更新

4)

[self.view layoutIfNeeded] 立即更新view的布局

这两个方法是对布局进行改变的方法。他们合作的原理和1)、2)一样。3)负责标记需要布局改变,4)来触发

-layoutSubviews

但是调用 4) 的时候会判断是 否需要更新布局的 flag ,就是如果没有调用3)有可能4)并不会触发layoutSubviews。所以在实践中3)、4)也最好一 起使用,才能保证布局更新。这两个方法加入动画块就可以实现动画布局的效果。 比如你更新好约束后,这样调用:

[UIView animateWithDuration:0.4 animations:^{
      [self.view setNeedsLayout];
      [self.view layoutIfNeeded];
}];

就可以动画改变布局。

 在viewcontroller中调用 3)和4)会重新触发viewWillLayoutSubviews,viewDidLayoutSubviews的过程,所以最好不要在这两个方法
 中加入布局的代码,应该完全依靠约束来保证布局,因为这两个方法在每次布局过程中都会被调用。

同时布局frame的计算过程是从 superview 到 subview 的。而 -layoutSubviews 方法被触发后,会对该 view 的 subviews 进行

 -layoutIfNeeded 

的递归操作。所以布局 frame 的计算是从 superView 到 subView 的。

这里要明白,-layoutSubviews方法是最后一步可以补救布局修改frame的地方,最好在前面的步骤中就通过约束来完成布局
,除非万不得已才在自定义 view中重载-layoutSubview方法来完成最后一步布局。这所有的过程都是前后逻辑依赖的,frame
的计算会依赖约束的计算,所以在布局的阶段可能会重新调用约束的计算的阶段。当最后布局完成后就是屏幕从上到下的渲染
过程。这个过程涉及到的就是下面的 5)。

5) 调用后会触发view的 -drawRect 方法重绘,和布局没有关系。调用这个方法后 -drawRect 方法何时调用系统决定,开发者则不用操心,系统对重绘有自己的优化方法。 实时绘图需要在

-touchBegan 

方法中调用 5)来实时刷新屏幕。

所以实践中的情况是:

a.如果手动直接改变了约束,直接调用布局更新方法 3)即可,因为 3)调用后在触发布局的时候会自动调用约束计算方法 2)计算最新的约束。

b.如果在某些情况下在重载 -updateViewConstraints 的方法中需要改变约束,调用 1),而且大多数情况下接着调用 3)。

c.如果在改变约束后需要马上重新布局,那么在上述的操作后立马调用 4)来使新的约束生效。在动画 block 中调用就会产生动画效果。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值