2016-03-02 00:00:00 +0000

frame与Autolayout(Masonry)的几点结论

在做开发的时候,UI适配方面老代码都是使用frame做UI布局,新的代码却是用的Autolayout,我们主要是用的三方库masonry写约束完成布局。在这个过程中。我一直有个错误的认识,Autolayout不会改变frame。网上看到很多blog也这么认为。这么认为多是由于设置完约束之后,打印frame的值为CGRectZero或者一个错误值造成的。但是在我调试一段代码时,情况却超出了我原来(错误)的认识。为什么打印的frame完全正确?

答案是设置约束后frame的更新并不是实时的,需要等到根据约束计算好view的位置和尺寸之后才会刷新frameAutolayout的本质是通过一套约束规则去确定一个viewsuperview中的位置和尺寸。既是位置和尺寸那不就是frame嘛。所以我通过文档和实验得出了以下几个结论:

  • Autolayout是一套关于view位置和尺寸的约束规则
  • Autolayout改变可以改变viewframe,但是frame的改变并不能改变Autolayout的约束规则(当translatesAutoresizingMaskIntoConstraints = YES时,会根据autoresizingMask的相应设置更新相应的约束,但是这很可能会与既有的约束冲突,iOS7很有可能crash。设置translatesAutoresizingMaskIntoConstraints = NO是推荐的做法,所以我们可以认为更改frame不会改变约束),约束应该通过约束更新的方式改变。想要在Autolayout改变后立即看到frame的变化,请调用以下代码来立即刷新UI的布局
- (void)setNeedsLayout;
- (void)layoutIfNeeded;
  • Autolayoutframe能否混用,答案是一定程度上可以,牢记上面一条两者之间的相互影响关系。在约束布局的UI视图中,混用frame布局,一定要先调用上面的这段代码,这样就能得到superView和相关view准确的frame。但是修改frame不会修改约束使得混用的情况的变得复杂很容易出错,所以还是大众化的建议:最好不要混用。
  • 在一些业务处理时,在约束布局后,需要获取view的宽高尺寸等信息,不用说,先调用上面的代码。这也可以说是一种混用的情况吧。
  • 一些人认为在viewDidLayoutSubviewsviewDidAppear 中布局已经确定,可以获取实际的frame,诚然如此。这样也比每次调通上面的代码效率高。但是这只适用于进入页面后布局不在变化的情况,假如在当前页面一些操作触发了约束变化,那么这种做法就不适用了。上面这段代码虽然效率低,但是适用范围更大。