如何在其 ViewController 的 viewDidAppear 之前确定 UIView 大小

How to determine UIView size before viewDidAppear of its ViewController

试图解决我现在遇到的一个问题

背景

假设我尝试计算一个应该完全适合 UIImageView 的 UIImage,该 UIImageView 在情节提要中使用约束进行布局。

imageView 的内容不应该被填充/纵横比适合...但完全适合框架。 因此我在 viewController

中有一个方法
- (UIImage *)calculatedImageForRect:(CGRect)imageRect

问题

我想确保 imageView 在视图可见后立即包含正确的图像,在简单的推送转换期间也是如此。 另外,我不想多次生成 UIImage,因为它相对昂贵。

这对于像 iPhone6 plus 这样具有不同屏幕分辨率的设备来说尤其有趣

显然 viewDidLoad 帧设置不正确。在这一点上,框架被设置为故事板的预览 - 例如表示 IPhone5 分辨率的设置。 viewWillAppear 也是如此。 这里的框架例如是 (10,10,300,100) <-- 我们称它为 wrong-frame

viewDidAppear 上框架是正确的 (10,10,394,100) = 正确框架 <-- 而不是 320 点宽度,iPhone6 Plus有414点。然而,这里已经太晚了,因为视图已经可见并且设置图像会导致闪烁(空图像 > 新生成的图像)​​。

我知道使用宽度的正确时间是 viewDidLayoutSubviews,首先用 wrong-frame 至少调用一次,然后在一个点调用使用 正确框架。 但正如我所说,我不想多次生成图像,所以这是两难选择:

如何判断右框是否可见?

当然,我可以通过使用 UIImageView 的尾随和前导约束从 [UIScreen mainScreen] 分辨率计算出正确的帧,但感觉很脏。

你不能使用viewDidLayoutSubviews的原因是,正如你所说,它可能被调用不止一次。 layoutSubviews.

也是如此

这是为什么?一个原因是因为基于约束的布局是一个迭代过程,可能涉及多次传递。例如,假设我强制布局视图 V,它在其视图层次结构中包含一个子视图 W,其中包含一个子视图 X。X 布局的第一个自动布局计算可能会改变约束,然后需要重新计算 W ,然后需要重新计算 X。这基本上不同于具有自动调整大小掩码的布局,后者是自上而下的,因此外部视图始终决定其子视图的布局。

但是,我相信(但不是 100% 肯定),如果您的所有布局代码都正确实施,那么这些多个布局通道都应该在一个回合内完成运行 循环。也就是说,当你通过调用layoutIfNeeded强制在V上布局来开始这个过程时,那么你可以确定W和X上的所有Auto Layout布局传递已经完成,一次layoutIfNeededreturns。没有 "needs layout" 或 "needs update constraint" 标志会被弄脏,等待下一轮 运行 循环完成工作。

这可能会为您指明解决方法。如果你在你的层次结构中强制顶层视图的早期布局(例如你正在转换到的视图控制器的根视图),那么当布局传递完成时 UIImageView 将有一个正确的框架,并且你可以使用那个框架来生成你的图像。

本质上,不是在最后可能的时刻进行布局,而是强迫它更早完成。然后你可以知道它什么时候完成,因为你启动了它并且可以通过等待 layoutIfNeeded 退出来看到过程的结束。然后你可以观察你关心的结果值。