I push a view controller (mainVC
) and add some subviews to it. Most of these views are built on-demand, as the user takes some action.
When I build each view, I refer to mainVC.view.bounds
to size the view. The ones that are built on demand size just fine, but the first one (which I add in viewDidLoad
) does not seem to account for either the hidden navigation bar or the unhidden toolbar - I'm not sure which.
Other questions seem to assure me that viewDidLoad is the correct place to refer to the bounds and to add these subviews. Am I misinformed? Logging yields the following:
In viewDidLoad
the bounds height is 548.
In viewWillAppear
the bounds height is 460 (-44 x 2). In viewWillAppear
I hide the navigation bar, but the height is the same before and after.
At all later times, the bounds height is 504 (-44 x 1).
Why is the bounds height not updated by the time I attempt to read it in viewDidLoad
?
The view controller lifecycle is described in View Controller Programming Guide for iOS.
In short, when -view
is called the first time, -viewDidLoad
is called. Even if the very first thing a view controller does to a view is set the frame, it still needs to access the view.
UIViewController *controller = [MyViewController myViewController];
// -viewDidLoad has not been called (if +myViewController doesn't call -view.)
UIView *view = [controller view];
// -viewDidLoad has been called.
view.frame = [UIApplication sharedApplication].delegate.window.bounds;
Even if you use controller.view.frame
the same logical sequence happens. -viewDidLoad
will always be a called with a freshly deserialized view that has not been embedded into the view hierarchy.
Update
It case it wasn't clear earlier, I was pointing out why the bounds of view are not set correctly in -viewDidLoad
. It is only after -viewDidLoad
does the view controller's view get added to the view hierarchy. This is when the final frame of the view is set.
If you must have the frame be the right dimensions, you can use IB to set the dimensions that you know you'll need or (if you don't use IB) set the frame in -loadView
. This approach is flawed because it statically sets the size of the frame to a value that may be changed after -viewDidLoad
is called (things like the in-call status bar).
Update 2
You need to split the adding subviews from positioning and sizing subviews.
If you are loading from a Storyboard or a Nib, then you are correct, additional views needed should be added in -viewDidLoad
. If you're loading programmatically, then all subviews are added in -loadView
.
The second task is positioning and sizing subviews. The preferred method is to use UIView.autoresizingMask, but for more precise layout, KVO view.bounds and adjust your custom subviews when view controller's view changes its size.