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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13079172/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 20:57:18  来源:igfitidea点击:

Unable to set frame correctly before viewDidAppear

objective-ciosuiviewviewdidloadviewdidappear

提问by nacross

I was wondering if anyone knows why when you set the frame of a subview in viewDidLoadand viewWillAppearthe changes do not take affect on the screen, but if you set it in viewDidAppearthey do?

我想知道是否有人知道为什么当您在其中设置子视图的框架viewDidLoad并且viewWillAppear更改不会在屏幕上生效,但是如果您将其设置在其中viewDidAppear呢?

In my case I am loading a custom xib with two tableviews then attempting to shift them down in viewDidLoadto allow space for another view which is added in viewDidLoadas it is not always necessary to display it.

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

The problem is when i set frame in viewDidLoador viewWillAppearit is set on the object, i can see by printing it out, but it is not reflected on screen. Moving my set frame calls to viewDidAppearwill cause everything to work as expected.

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

Is it wrong to think I should be able to set the frame in viewDidLoad?

认为我应该能够设置框架是错误的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;
}

回答by Leon Storey

viewDidLoad is called when the class is loaded however no ui elements have been initialised and therefore any attempt to reference them will be overwritten or unavaliable during the initialisation process which happens between the viewDidLoad and viewDidAppear calls. Once all ui element have been initalised and drawn viewDidAppear is called.

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

viewDidLoad - Called after the controller's view is loaded into memory

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

At this point the view isn't within the view hierarchy.

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

viewWillAppear - Notifies the view controller that its view is about to be added to a view hierarchy.

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

Again, the view is yet to be added to the view hierarchy.

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

viewDidAppear - Notifies the view controller that its view was added to a view hierarchy.

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

Only then is the view added to the view hierarchy.

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

Update

更新

The viewDidLayoutSubviewsis the most appropriate place to modify the UI before it actually appears on the screen.

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

viewDidLayoutSubviews - Notifies the view controller that its view just laid out its subviews.

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

回答by BollMose

See this thread When is layoutSubviews called?
When use autolayout, framework do not call layoutSubviews automatically. That is very important. From ref:

请参阅此线程何时调用 layoutSubviews?
使用自动布局时,框架不会自动调用 layoutSubviews。这是非常重要的。来自参考:

  • init does not cause layoutSubviews to be called (duh)
  • addSubview: causes layoutSubviews to be called on the view being added, the view it's being added to (target view), and all the subviews of the target. ...
  • init 不会导致 layoutSubviews 被调用(废话)
  • addSubview:导致 layoutSubviews 在被添加的视图、它被添加到的视图(目标视图)以及目标的所有子视图上被调用。...


If you add subview in viewDidLoad, layoutSubviews called before viewDidAppear, and you can get the correct size of subviews. But if you do nothing, layoutSubviews will be called after viewDidAppear. It's up to your code.


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

回答by Mohshin Shah

in viewWillAppear()

在 viewWillAppear()

just call layoutIfNeeded() once for the view whose frame you want to get.

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

if tableView then tableView.layoutIfNeeded() for exmple

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