Domanda

My app has a view controller that due to the fact it plays its own custom transition animations, provides its own standalone UINavigationBar view at the top (As opposed to using a UINavigationController).

When using an iPhone, and when rotating the device, I would like the UINavigationBar to automatically apply the landscape UIBarMetrics properties (eg, change height, change the background image, resize the buttons etc), but by default, it does not. This is a problem on iOS 7, since even if I manually change the height of the UINavigationBar, the UIBarButtonItem elements don't change their vertical positions.

Is there a way to manually 'tell' the UINavigationBar to apply specific bar metric properties to itself? Or is that actually an implementation inside UINavigationController, and not UINavigationBar?

È stato utile?

Soluzione 2

The bar metrics properties you can set on a UINavigation bar are things like background image and the title vertical position. Heigh and width need to be set from within your view controller.

If you need to manually tell the navigation bar to change it's size when the orientation changes you can implement the method - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration1 in your view controller and change the size there.

Another option you can use is to use autolayout to specify that the width of your navigation bar is pinned to the left and right sides of its superview and let it figure out how wide it should be. For example

UINavigationBar *bar = [[UINavigationBar alloc] init];
bar.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:bar];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[bar]|"
                                                                     options:0
                                                                     metrics:nil
                                                                       views:NSDictionaryOfVariableBindings(bar)]];

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[bar(44)]|"
                                                                  options:0
                                                                  metrics:nil
                                                                    views:NSDictionaryOfVariableBindings(bar)]];

Altri suggerimenti

After various testing and trial and error after asking this question, I eventually worked out a solution that fixed all of my issues, so I'll post it here under the solution I'd previously accepted.

When my app is displayed in landscape on an iPhone, I wanted the UINavigationBar at the top to shrink to the standardly accepted 32 points high, as is the case with any apps that use the UINavigationController class. However, as I am not using a UINavigationController for this particular view (for varying reasons of feasibility), I needed to implement this manually.

To account for the new transparent status bar in iOS 7, I adjusted the origin and size of the UINavigationBar so it encompassed both the bounds of the status bar, and the normal UINavigationBar region (ie, so the UINavigationBar frame origin was {0,0}, and the height was 52 points.)

Unfortunately, this happened:

The issue with the misaligned content

While the bar itself is rendering at the proper position and height, all of the content in the bar, including the title and buttons are not positioned properly, being much too high, almost touching the status bar content.

It was pretty obvious what was happening. The navigation bar content is being vertically aligned to its own middle, completely disregarding the presence of the status bar content.

When I tested the same orientations with a normal UINavigationController, this was not the case, and the title and buttons in the UINavigationBar from the UINavigationController worked absolutely fine. Apple had done SOMETHING in there that wasn't part of the normal UINavigationBar implementation.

Going on this, I picked apart the view layout hierarchy of a UINavigationControllerto see what was happening to the UINavigationBar in there (Mainly calling a lot of NSLog() statements that would dump the subviews of the navigation bar.)

This is what I discovered:

The content, properly aligned

From the looks of it, Apple have employed a relatively sneaky hack to achieve this effect. It turns out the actual UINavigationBar is actually placed right below the status bar (ie at point {0,20}) and only has a height of 32 points. Then, what happens is a private subview inside the UINavigationBar in charge of rendering the background is extended upwards, outside of the bounds of the navigation bar to encompass the region behind the status bar (ie, its origin is {0, -20}, and its height is 52 points, local to the navigation bar's subview coordinate space).

So by doing that, not only does the content vertically align properly, but the translucent effect still extends behind the status bar.

Anyway, after I discovered this, it was pretty straightforward to write a solution. All I needed to do was reposition and resize the UINavigationBar back to how I had it iOS 6 (ie, 20 points down, and only 32 points high), and then implement a UINavigationBar subclass that override the layoutSubviews method, grabbed the internal background view (Doing a quick subview check for a view with a class name that matched "Background"), and then manually extended it.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top