在 viewDidAppear 之前无法正确设置框架

Posted

技术标签:

【中文标题】在 viewDidAppear 之前无法正确设置框架【英文标题】:Unable to set frame correctly before viewDidAppear 【发布时间】:2012-10-26 00:16:55 【问题描述】:

我想知道是否有人知道为什么当您在viewDidLoadviewWillAppear 中设置子视图的框架时,更改不会在屏幕上生效,但如果您在viewDidAppear 中设置它,他们会这样做吗?

在我的例子中,我正在加载一个带有两个表视图的自定义 xib,然后尝试在 viewDidLoad 中将它们向下移动,以便为 viewDidLoad 中添加的另一个视图留出空间,因为并不总是需要显示它。

问题是当我在viewDidLoadviewWillAppear 中设置框架时,它设置在对象上,我可以通过打印看到它,但它没有反映在屏幕上。将我设置的框架调用移动到 viewDidAppear 将使一切按预期工作。

认为我应该能够在viewDidLoad 中设置框架是错误的吗?

- (id)init 
    if ( self = [super initWithNibName:@"MyView" bundle:nil] ) 

    return self;


- (void)viewDidLoad 
    [super viewDidLoad];
    self.descriptionWebView = [[[UIWebView alloc] initWithFrame:CGRectMake( 0, 0, self.view.frame.size.width, 200 )] autorelease];

    [self.view addSubview:self.descriptionWebView];

    self.tableView1.autoresizingMask = UIViewAutoresizingNone;
    self.tableView2.autoresizingMask = UIViewAutoresizingNone;

    [self.descriptionWebView loadRequest:[NSURLRequest requestWithURL:[[NSBundle mainBundle] URLForResource:@"...." withExtension:@"html"]]];

    table1LocationWithHeader = CGRectMake( self.tableView1.frame.origin.x, 200, self.tableView1.frame.size.width, self.tableView1.frame.size.height - 200 );
    table2LocationWithHeader = CGRectMake( self.tableView2.frame.origin.x, 200, self.tableView2.frame.size.width, self.tableView2.frame.size.height - 200 );

    //this will NOT work
    self.tableView1.frame = table1LocationWithHeader;
    self.tableView2.frame = table2LocationWithHeader;


- (void)viewWillAppear:(BOOL)animated 
    [super viewWillAppear:animated];

    //this will NOT work
    self.tableView1.frame = table1LocationWithHeader;
    self.tableView2.frame = table2LocationWithHeader;



- (void)viewDidAppear:(BOOL)animated 
    [super viewDidAppear:animated];

    //this WILL work
    self.tableView1.frame = table1LocationWithHeader;
    self.tableView2.frame = table2LocationWithHeader;



//I added these after comments for stack overflow users, it seems like viewDidLayoutSubviews is the best place to set the frame

- (void)viewWillLayoutSubviews 
    [super viewWillLayoutSubviews];

    //this will NOT work
    self.tableView1.frame = table1LocationWithHeader;
    self.tableView2.frame = table2LocationWithHeader;


- (void)viewDidLayoutSubviews 
    [super viewDidLayoutSubviews];

    //this WILL work
    self.tableView1.frame = table1LocationWithHeader;
    self.tableView2.frame = table2LocationWithHeader;

【问题讨论】:

你可以显示你的代码吗? UIViewController returns invalid frame? 的可能重复项 注意!您的 viewWillAppear 调用 [super viewDidAppear]; 看起来像复制粘贴错误。 【参考方案1】:

viewDidLoad 在类加载时调用,但是没有初始化任何 ui 元素,因此在 viewDidLoad 和 viewDidAppear 调用之间发生的初始化过程中,任何引用它们的尝试都将被覆盖或不可用。一旦所有 ui 元素都被初始化并绘制 viewDidAppear 就会被调用。

viewDidLoad - 在控制器的视图加载到内存后调用

此时视图不在视图层次结构中。

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

同样,视图尚未添加到视图层次结构中。

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

只有这样,视图才会添加到视图层次结构中。

更新

viewDidLayoutSubviews 是在 UI 实际出现在屏幕上之前修改 UI 的最合适位置。

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

【讨论】:

我刚试了一下,viewDidLayoutSubviews 似乎是设置框架的最佳位置。感谢您帮我解决这个问题。 @Sulthan 我认为当您在界面构建器中设置了与您设置的任何框架冲突的约束时,就会出现此问题。这必须发生在 viewWillLayoutSubviews 和 viewDidLayoutSubviews 之间。 viewDidLayoutSubviews 太棒了!我已经为 ios 开发了两年了,这是我第一次听说它。很好的答案! +1 我一直看到这个答案,其中一个大问题被忽略了。 viewDidLayoutSubviews 被多次调用(其中一个,在@DienBell 解释的每个添加的子视图上)。如果您在那里进行许多帧计算,它将进行多次。远非整洁。可以放置一个标志,但第一次调用可能会有一个不完整的帧。所以你真的想要 last 调用。但我想不出一种方法来实现这一点。检查self.view.frame 不是CGRectZero 可以工作,但同样,远非整洁。 @Noitidart 不。我“希望”苹果有一天会解决这个问题。我想由于某些帧依赖于其他帧,viewDidLayoutSubviews 是正确的位置,但我主要使用UIScreen.main.bounds 来获取屏幕尺寸(始终正确设置并且不会改变)。查看我的帖子:***.com/questions/33942215/…【参考方案2】:

看到这个帖子When is layoutSubviews called? 当使用自动布局时,框架不会自动调用 layoutSubviews。这是非常重要的。来自参考:

init 不会导致 layoutSubviews 被调用 (duh) addSubview:导致 layoutSubviews 在被添加的视图、它被添加到的视图(目标视图)以及目标的所有子视图上调用。 ...

如果在viewDidLoad中添加子视图,layoutSubviews在viewDidAppear之前调用,就可以得到正确大小的子视图。但是如果你什么都不做,layoutSubviews 会在 viewDidAppear 之后被调用。这取决于您的代码。

【讨论】:

【参考方案3】:

在 viewWillAppear() 中

只需为要获取其框架的视图调用一次 layoutIfNeeded()。

如果是 tableView 然后是 tableView.layoutIfNeeded() 例如

【讨论】:

以上是关于在 viewDidAppear 之前无法正确设置框架的主要内容,如果未能解决你的问题,请参考以下文章

在 viewDidAppear 之前获取 scrollView 的内容大小

iOS 5 - 空白 UIWebView 在 ViewDidAppear 之前导致长时间延迟

JFrame 无法正确显示

iPhone 5 中的 viewDidAppear 高度为 656

自动布局:ViewDidAppear 中的帧大小不正确

无法使用 Swift 为 UILabel 设置动画