`viewDidLayoutSubviews`中的帧计算

时间:2015-11-26 15:29:43

标签: ios ios9

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

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

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

我们习惯拥有一个' framesAreSet' flag(初始化为false)和一个检查,如果frame不为零(类似于self.view.frame.size.width != 0)和' framesAreSet'是假的,它进去,转动旗帜并只计算一次。类似的东西:

- (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查看的问题)

3 个答案:

答案 0 :(得分:1)

该应用每次绘制只获得一个didLayoutSubviews(截至该点,视图状态更改仅记录setNeedsLayout)。从这个意义上讲,didLayoutSubviews 是您对didCompleteLayoutOfSubviews的看法。绘制后,如果发生另一个视图状态更改,则布局再次不完整。

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

答案 1 :(得分:1)

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

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

如果性能确实对您很关键,那么您可能希望将计算框架缓存为某些字典,如果边界尺寸发生变化,则无效。

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

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

答案 2 :(得分:0)

你可以使用dispatch once token(GCD)计算viewDidLayoutSubviews方法中的帧,如果帧被初始化,一旦这不会进入你的dispatchonce块。