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

nac*_*oss 41 objective-c uiview viewdidload viewdidappear ios

我想知道是否有人知道为什么当你设置子视图的框架viewDidLoad并且viewWillAppear更改不会影响屏幕,但如果你设置viewDidAppear它们呢?

在我的情况下,我正在加载一个带有两个tableviews的自定义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;
}
Run Code Online (Sandbox Code Playgroud)

Leo*_*rey 95

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

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

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

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

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

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

只有这样才能将视图添加到视图层次结构中.

更新

viewDidLayoutSubviews是最合适的地方来修改UI实际上出现在屏幕上了.

viewDidLayoutSubviews - 通知视图控制器其视图刚刚布置了其子视图.

  • 我刚试了一下,viewDidLayoutSubviews似乎是设置框架的最佳位置.谢谢你帮我澄清一下. (8认同)
  • 我一直在看这个答案,其中一个大问题被忽略了.多次调用`viewDidLayoutSubviews`(对于一个,在@DienBell解释的每个添加的子视图中).如果你在那里做了很多帧计算,它会多次执行.远非整洁.可以放置一个标志,但第一个调用可能会有一个不完整的帧.所以你真的想要_last_电话.但我想不出有办法实现这一目标.检查`self.view.frame`不是'CGRectZero`可以工作,但再次,远非整洁. (4认同)
  • @Sulthan我认为当您在界面构建器中设置的约束与您正在设置的帧相冲突时会出现此问题.这必须发生在viewWillLayoutSubviews和viewDidLayoutSubviews之间. (3认同)
  • `viewDidLayoutSubviews`太棒了!我已经开始为iOS开发两年了,这是我第一次听说过它.很棒的答案!+1 (2认同)