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

我在我的应用程序中发现了一个奇怪的行为,在我的视图控制器对 viewWillAppear:viewDidAppear:的调用之间,一个已连接的 IBOutlet具有其已连接的视图帧。下面是我的 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方法中使用视图进行设置,但是如果内容在出现在屏幕上之前不能进行更改,那似乎就没有什么用处了。会发生什么事?

43392 次浏览

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:

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

viewDidLayoutSubviews

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

Autolayout made a huge change in how we design and develop the GUI of our views. One of the main differences is that autolayout doesn'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)viewDidLayoutSubviews method of your view controller.
This method is called when the autolayout engine has finished to calculate your views' frames.

call

self.scrollView.layoutIfNeeded()

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

In my case, moving all frame related methods to

override func viewWillLayoutSubviews()

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