iOS自动布局

Storyboard中用Auto Layout的“Bug”

在storyboard中使用自动布局,根控制器为一个UITableView,所有的cell的行高根据cell内容的多少动态变化(类似微博、微信朋友圈等应用)。

链接地址:demo

据此,我根据Cell的内容获取Cell内的labelUIImageView的frame,然后在layoutSubview方法中根据frame来计算最终的行高,然后,在controller中通过代理方法拿到行高。
这是很常规的一个开发思路,可是在storyboard开发中使用prototype(原型)cell的方式来实现却遇到了问题...

1.首先,我在StoryBoard里面使用prototype(原型)cell,而且没有改ViewController属性检测器中的simulation Metricssize

不设置此处的尺寸

2.然后,我给cell中的所有的子控件设置了约束,并且确认无误,没有警告和错误,然后我update了一下所有控件的frame(注意:这里如果不更新所有控件的frame的话,storyboard便会给你报黄色警告,提示你期望的大小和真实的大小不相同,截图如下

ExpectedFrame和ActualFrame的警告

3.解决上面的办法也很简单,点击警报,点击Fix(修复)或者选中所有的控件,点击下方设置约束按钮中最右边的一个,选择"Update Frame"就可以了

修复上述警报的冲突

4.设置完约束,我需要分别实现模型中的逻辑,和自定义的cell中的逻辑

4.1. 模型类从网络获取数据,使用的是异步子线程,下载完成后回调,切换主线程给ViewController中的数据数组赋值。

4.2. 给自定的cell内的子控件赋值写在了UITableViewDatasource的返回cell的方法中,但是,要求cell内的副标题Label的显示或不显示,取决于主标题Label的行数,如果主标题只显示1行,那么就显示副标题,相反,就不显示副标题。

这个逻辑才是重点
我在cell的layoutSubviews方法中获取主标题的frame,可是,无论如何改变主标题Label的约束,通过layoutSubviews方法获取到的frame始终不变。这里引起了我的怀疑,因为layoutSubviews方法的解释是当父控件的frame发生改变的时候,会调用此方法。但是实际来看在layoutSubviews方法中cell内的控件的frame仍然未发生变化,还是storyboard中Update Frames之后的值!!

但是当执行完layoutSubviews方法后,界面就已经能够正常地显示出来了,并且大小都正常,但是在layoutSubviews方法里打印的Label的frame却不正确,这就很奇怪!

副标题不正常的情况

于是,我继续猜想,这可能是由于约束设置完成之后,需要通过很多计算,而产生一个时间差,所以就使得在layoutSubviews方法执行的那一瞬间,无法立即计算出主标题的正确的frame。

接着,我寻找其他的思路,发现有一个方法layoutIfNeeded,这个方法的解释是:Lays out the subviews immediately.在调用这个方法后,立即布局该控件的子控件,因此,我试着在调用主标题Label的getter方法之前,调用layoutIfNeeded这个方法,结果就成功了。

iOS自动布局_第1张图片
正常的label显示情况.jpg

得出总结:当父控件的frame发生变化的时候,会调用它的layoutSubviews方法,但是,此时我们的约束还没有计算好所有子控件的frame值,所以,要在layoutSubviews方法内获取子控件的frame,可能就会拿到一个错误的frame值

在解决这个Bug的同时,还遇到一个小插曲,当属性检测器使用的是默认的大小的时候,如果勾选了storyboard中的ViewController属性检测器的Refreshing中的Enabled选项,则会出现在刚开始进入应用的时候,就会加载self.refreshControl 的title 内容

iOS自动布局_第2张图片
使用storyboard默认的大小

但是当我不进行其他任何的操作,而仅仅只是把属性检测器中模拟器的size属性设置为一个其他的大小时,就不会有上述的效果了

设置一个指定的尺寸之后.png

你可能感兴趣的:(iOS自动布局)