85

我在我的应用程序中发现了一个奇怪的行为,其中IBOutlet连接的视图在我的视图控制器调用viewWillAppear:viewDidAppear:. 这是我的UIViewController子类中的相关代码:

-(void)viewWillAppear:(BOOL)animated {
    NSLog(@"%@", self.scrollView);
}

-(void)viewDidAppear:(BOOL)animated {
    NSLog(@"%@", self.scrollView);
}

以及生成的日志输出:

MyApp[61880:c07] <UIScrollView: 0x1057eff0; frame = (0 0; 0 0); clipsToBounds = YES; autoresize = TM+BM; gestureRecognizers = <NSArray: 0x10580100>; layer = <CALayer: 0x1057f210>; contentOffset: {0, 0}>
MyApp[61880:c07] <UIScrollView: 0x1057eff0; frame = (0 44; 320 416); clipsToBounds = YES; autoresize = TM+BM; gestureRecognizers = <NSArray: 0x10580100>; layer = <CALayer: 0x1057f210>; contentOffset: {0, 0}>

这清楚地表明框架在两个调用之间发生了变化。我想用viewDidLoad方法中的视图进行设置,但如果内容在屏幕上之前无法更改,那似乎毫无用处。会发生什么?

4

4 回答 4

156

文档中:

viewWillAppear:

通知视图控制器其视图即将添加到视图层次结构中。

viewDidAppear:

通知视图控制器其视图已添加到视图层次结构中。

因此,子视图的框架尚未设置在viewWillAppear

在视图呈现到屏幕之前修改 UI的适当方法是:

viewDidLayoutSubviews

通知视图控制器它的视图刚刚布置了它的子视图。

于 2013-07-14T09:06:52.510 回答
112

Autolayout对我们如何设计和开发视图的 GUI 做出了巨大的改变。主要区别之一是它autolayout不会立即更改我们的视图大小,而是仅在触发时,这意味着在特定时间,但我们可以强制它立即重新计算我们的约束或将它们标记为“需要”布局。它像-setNeedDisplay.
对我来说最大的挑战是要理解并接受这一点,我们不再需要使用自动调整大小的蒙版,而框架在放置我们的视图时已成为无用的属性。我们不再需要考虑视图位置,但我们应该考虑我们希望如何在彼此相关的空间中看到它们。
当我们想要混合旧的自动调整大小蒙版和自动布局时,就会出现问题。我们应该尽快考虑自动布局的实现,并尽量避免在基于自动布局的视图层次结构中混合旧方法。
有一个只使用自动调整大小掩码的容器视图很好,例如视图控制器的主视图,但如果我们不尝试混合则更好。
我从未使用过故事板,但很可能它是正确的。使用自动布局,您的视图框架在自动布局引擎开始计算时设置。尝试在- (void)viewDidLayoutSubviews视图控制器的方法 super 之后问同样的事情。
当自动布局引擎完成计算视图的帧时调用此方法。

于 2013-07-14T09:46:57.130 回答
9

称呼

self.scrollView.layoutIfNeeded()

在你的viewWillAppear方法中。之后您可以访问它的框架,它将具有与您打印的相同的值viewDidAppear

于 2016-10-11T11:45:09.817 回答
4

就我而言,将所有与框架相关的方法移动到

override func viewWillLayoutSubviews()

工作完美(我试图从情节提要修改约束)。

于 2017-05-28T00:11:13.097 回答