如何在视图控制器的viewDidAppear之前确定UIView的大小

7

我一直在试图解决一个问题

背景

假设我想要计算出一个完美适应于Storyboard中使用约束进行布局的UIImageView的UIImage。

这个imageView的内容不应该填充或按比例缩放,而是完美地适应框架。因此,在我的viewController中有一个方法。

- (UIImage *)calculatedImageForRect:(CGRect)imageRect

问题

我希望在视图变得可见时,确保imageView已经包含了正确的图像,因此在简单的推送转换期间也是如此。 此外,我不想多次生成UIImage,因为它的成本相对较高。

这在像iPhone6 Plus这样的设备上特别有趣,因为它们具有不同的屏幕分辨率。

显然,在viewDidLoad中,框架没有设置正确。在此时刻,框架被设置为Storyboard预览中的设置 - 例如为表示iPhone5分辨率而设置。对于viewWillAppear也是同样的情况。在这里,框架将是(10,10,300,100)。让我们称其为wrong-frame

viewDidAppear时,框架是正确的(10,10,394,100)= correct-frame <-- iPhone6Plus的宽度为414点,而不是320点。尽管如此,在这里为时已晚,因为视图已经可见,并且设置图像将导致闪烁(空白图像>新生成的图像)。

我知道使用宽度的正确时间是viewDidLayoutSubviews,它首先至少一次以wrong-frame被调用,然后在某一时刻以correct-frame被调用。但是,正如我所说,我不想多次生成图像,这里就是两难:

我怎样才能在它可见之前确定right-frame

当然,我可以通过使用UIImageView的尾部和首部约束来计算正确的框架,从[UIScreen mainScreen]分辨率中工作,但这感觉很糟糕。


那么你问题的实质是想找出如何在特定视图(在这种情况下是UIImageView)最终设置为正确的框架之后,但在呈现在屏幕上之前被通知吗? - algal
是的,那正是我想知道的。 - MarkHim
1个回答

11
你不能使用viewDidLayoutSubviews的原因是,正如你所说,它可能会被调用多次。同样适用于layoutSubviews
为什么会这样呢?一个原因是因为基于约束的布局是一个迭代过程,可能需要多个步骤。例如,假设我强制布置视图V,它包含在其视图层次结构中的子视图W,其中包含一个子视图X。布局X的第一次自动布局计算可能会改变约束条件,然后需要重新计算W,再需要重新计算X。这基本上不像具有自动调整大小掩码的布局,它是自上而下的,因此外部视图始终控制其子视图的布局。
然而,我认为(但不是100%确定),如果所有的布局代码都正确实现,那么这些多重布局传递应该都在一次运行循环的内部进行。也就是说,当您通过调用layoutIfNeeded在V上强制进行布局时,可以确保 W和X的所有自动布局布局传递都已完成,一旦layoutIfNeeded返回。没有“需要布局”或“需要更新约束”标志保持脏等待下一轮运行循环完成工作。
这可能指向了您的解决方案。如果在您的层次结构中强制提前布局顶级视图(例如您正在转换到的视图控制器的根视图),那么当该布局传递完成时,UIImageView将具有正确的框架,您可以使用该框架生成您的图像。
从本质上讲,您不是在最后一刻进行布局,而是强制它提前完成。然后,您可以知道它何时完成,因为您启动了它,并且可以通过等待layoutIfNeeded退出来看到该过程的结束。然后您可以观察所关心的结果值。

3
说实话,我没想到这会奏效,但它确实奏效了。现在我在viewWillAppear:中调用layoutIfNeeded,正如你所描述的那样,所有的子视图在之后都被正确地布局了。非常感谢你的答案,algal。 - MarkHim
简单重申一下,在你的 viewWillAppear 方法中,先调用 self.view.layoutIfNeeded,然后再添加任何调整大小的代码。 PS:我写这篇文章更多是为了自己而不是别人,因为我知道将来某一天我会回头看这篇文章哈哈。 - Eric

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接