Search code examples
iosrotationuinavigationbarautolayout

UINavigationBar rotation and auto layout


With regards to designing your own view Controller by inserting a UINavigationBar into the scene, I have found many references to questions regarding how the frame height does not change when rotating the device. This is in contrast to how Apple utilizes the UINavigationBar within it's navigation controller where the height of the bar does change upon rotation.

While there have been suggestions which do in fact show how to change the height to be consistent with what Apple does, all the answers do not address proper relationships to other views in the scene. In particular, when constructing a scene that utilizes autoLayout, you should never have to adjust the frame - auto layout is suppose to take care of this for you through the constraints you define.

For example, one suggestion was to do this:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 
{
    [self.navigationBar performSelector:@selector(sizeToFit) withObject:nil afterDelay:(0.5f * duration)];
}

While this will change the size, the relationship to other views is no longer correct. Although the poster in the above example did provide a solution to account for adjusting the relationship, this was more of a hard-coded approach, not one Apple likely suggests, i.e. not an autoLayout-friendly solution.

Through experimentation, I noticed that when rotating the device, the intrinsicContentSize did in fact change properly, but the frame did not. In noticing this, I tried the following:

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];

    CGRect frame = self.navigationBar.frame;
    frame.size.height = self.navigationBar.intrinsicContentSize.height;
    self.navigationBar.frame = frame;
}

While this did properly change the size, like the above example, it too resulted in incorrect view relationships.

Specifically, my device in landscape:

enter image description here

Then switching to portrait:

enter image description here

Is anyone aware of how Apple wants us to address UINavigationBar layout using constraints?


Solution

  • Just make a vertical spacing constraint between your button and the top layout guide. This can be done in IB by control dragging from the button to the bottom of the navigation bar. Very simple, no code necessary.

    After Edit: If you add a stand alone navigation bar, you do need some code (as far as I know) to get the behavior you get automatically with a navigation controller. The way I did this is to add a navigation bar, and give it constraints to the sides of the superview, a vertical constraint to the top layout guide, and a fixed height of 44 points. I made an IBOutlet to this constraint (called heightCon in the code below). The button has a centerX constraint and a vertical spacing constraint to the navigation bar.

    - (void)viewWillLayoutSubviews {
        self.heightCon.constant = (self.view.bounds.size.height > self.view.bounds.size.width)? 44 : 32;
    }