`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块。