ios viewWillAppear: 和 viewDidAppear 之间的视图框架变化:

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17637523/
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-31 00:20:02  来源:igfitidea点击:

View frame changes between viewWillAppear: and viewDidAppear:

iphoneiosobjective-cuiscrollview

提问by Jumhyn

I have discovered a strange behavior in my application, where a connected IBOutlethas its connected view's frame between the calls in my view controller to viewWillAppear:and viewDidAppear:. Here is the relevant code in my UIViewControllersubclass:

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

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

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

and the resulting log output:

以及由此产生的日志输出:

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}>

Which clearly shows that the frame is changing between the two calls. I wanted to do setup with the view in the viewDidLoadmethod, but if the content is not available for me to change until it is on the screen, that seems pretty useless. What could be happening?

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

回答by George Sachpatzidis

From the documentation:

文档:

viewWillAppear:

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

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

viewDidAppear:

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

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

As a result the frames of the subviews aren't yet set in the viewWillAppear:

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

The appropriate method to modify your UI before the view is presented to the screenis:

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

viewDidLayoutSubviews

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

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

回答by Andrea

Autolayoutmade a huge change in how we design and develop the GUI of our views. One of the main differences is that autolayoutdoesn't change our view sizes immediately, but only when is triggered, that means at a specific time, but we can force it to recalculate our constraints immediately or mark them as "in need" of layout. It works like -setNeedDisplay.
The big challenge for me was to understand and accept that, we do not need to use autoresizing masks anymore, and frame has become a useless property in placing our views. We do not need to think about view position anymore, but we should think how we want to see them in a space related to each other.
When we want to mix old autoresizing mask and autolayout is when problems arise. We should think about autolayout implementation really soon and try to avoid to mix the old approach in a view hierarchy based on autolayout.
Is fine to have a container view that uses only autoresizing masks, such as a main view of a view controller, but is better if we do not try to mix.
I never used storyboard, but most proably it is correct. Using Autolayout, frame of your views are set when the autolayout engine starts its calculation. Try to ask the same thing right after super of - (void)viewDidLayoutSubviewsmethod of your view controller.
This method is called when the autolayout engine has finished to calculate your views' frames.

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

回答by andrei

call

称呼

self.scrollView.layoutIfNeeded()

self.scrollView.layoutIfNeeded()

in your viewWillAppearmethod. Afterwards you can access it's frame and it will have the same value as you print in viewDidAppear

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

回答by Siddhesh Mahadeshwar

In my case, moving all frame related methods to

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

override func viewWillLayoutSubviews()

worked perfectly(I was trying to modify constraints from storyboard).

工作完美(我试图从故事板修改约束)。