`viewDidLayoutSubviews`中的帧计算

首先,我要提一下,这主要是效率问题。

关于在哪里进行框架计算有很多讨论,其中viewWillAppear太早而viewDidAppear太晚(视图已经可见)。

常见的答案是在viewDidLayoutSubviews进行帧计算。 问题是,它被多次调用。 更糟糕的是,最精确的呼叫,即所有帧都具有最终大小的呼叫是最后一个。 据我所知,没有办法知道最后一个是哪个电话。

我们使用’framesAreSet’标志(初始化为false)和一个检查,如果frame不为零(类似于self.view.frame.size.width != 0 ),’framesAreSet’为false,则进入,转动旗帜并只计算一次。 就像是:

 - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; if (self.view.frame.size.width != 0 && !framesAreSet) { framesAreSet = true; //Calculate frames here } } 

这看起来不错,但实际上,检查self.view.frame.size.width != 0类的东西并不能保证确实设置了帧。 viewDidLayoutSubviews将被调用之后的事实表明某些帧未设置为其最终状态。

有一个viewCompleteLayoutSubviews会很棒。 当所有帧都被设置并且视图还不可见时,有什么最好的方法可以实现“一次性”帧计算?

(这可能是使用NSConstraints的视图的问题)

该应用程序每次绘制只获得一个didLayoutSubviews (截至该点,视图状态更改仅通过setNeedsLayout )。 从这个意义上说, didLayoutSubviews 你对didCompleteLayoutOfSubviews的想法。 绘制后,如果发生另一个视图状态更改,则布局再次不完整。

换句话说,didLayout调用的数量不依赖于子视图添加或帧更改的数量,它取决于绘制的数量(不要与运行循环混淆)。 在绘制之前,如果设置了needsLayout标志,则无论视图层次结构重新排列多少,layoutSubviews和didLayoutSubviews都将被调用一次。

您应该始终为视图当前具有的维度重新布局。

您设置帧,然后旋转设备。 你需要重新计算框架吗? 当然,边界大小已经改变了! 你正在使用framesAreSet做出危险的假设。

如果性能确实对您很关键,那么您可能希望将计算帧缓存到某个字典中,如果边界大小发生更改,则会使这些字段无效。

但是你肯定不会仅仅执行一次布局。

另一种方法是使视图控制器的view成为自定义类的实例,并在其中覆盖-layoutSubviews

您可以使用dispatch once token(GCD)在viewDidLayoutSubviews方法中计算帧,如果帧未初始化,则不会进入dispatchonce块。