Position of navigation bar for modal view - iOS7

23,497

Solution 1

The best way to overcome this in iOS 7 is by conforming to the new UIBarPositioningDelegate protocol.

You connect the delegate of your NavigationBar to your view controller (set your view controller as the delegate for the navigation bar either through storyboard or through code) and conform to that protocol and by implementing the method

-(UIBarPosition)positionForBar:(id<UIBarPositioning>)bar { return UIBarPositionTopAttached; }

You can remove the top gap in the view controller. You need to place the bar 20 points below the top edge

Solution 2

Figured out the 3 options for solving this problem.

Option 1: Resize the Nav Bar

float currentVersion = 7.0;
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= currentVersion) {
    // iOS 7
    self.navBar.frame = CGRectMake(self.navBar.frame.origin.x, self.navBar.frame.origin.y, self.navBar.frame.size.width, 64);
}

Option 2: Hide the Status Bar

For example, in the modal view where you want to hide the status bar

Add this method

- (BOOL)prefersStatusBarHidden
{
    return YES;
}

In viewDidLoad add

float currentVersion = 7.0;

if ([[[UIDevice currentDevice] systemVersion] floatValue] >= currentVersion) {
    [self prefersStatusBarHidden];
    [self performSelector:@selector(setNeedsStatusBarAppearanceUpdate)];
}
else {
    [[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
}

Now, when you dismiss the modal view, and you want your status bar back. Add this in viewWillAppear

    float currentVersion = 7.0;

if ([[[UIDevice currentDevice] systemVersion] floatValue] >= currentVersion) {
    [self prefersStatusBarHidden];
    [self performSelector:@selector(setNeedsStatusBarAppearanceUpdate)];
    NSLog(@"ios7");
}
else {
    [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
}

and this, but return NO this time

- (BOOL)prefersStatusBarHidden
{
    return NO;
}

Option 3: Embed in Nav Controller

Select your modal view, just embed that in a Navigation Controller.

enter image description here

Solution 3

In Swift:

The best way to overcome this in iOS 8.1 and Swift is by conforming to the new UIBarPositioningDelegate protocol.

You connect the delegate of your NavigationBar to your view controller and conform to that protocol and by calling the method:

func positionForBar(bar: UIBarPositioning) -> UIBarPosition  {
    return UIBarPosition.TopAttached
}

You can remove the top gap in the view controller. You need to place the bar 20 points below the top edge.

Solution 4

For Swift3 use following..

func position(for bar: UIBarPositioning) -> UIBarPosition{
    return .topAttached;
}
Share:
23,497
DogCoffee
Author by

DogCoffee

Swift - iOS Dev MEAN Stack Dev

Updated on September 14, 2020

Comments

  • DogCoffee
    DogCoffee almost 4 years

    In a navigation controller, you automatically get the correct colour and position of a navigation bar as expected.

    like this

    enter image description here

    But in modal view, when you drag in a navigation bar, you can position it right at the top, which is too close to the carrier / battery info.

    enter image description here

    So you can drag it down, guess how far so it matches the position of the automatically created one, but then you have a colour discrepancy. I have tried changing status bar settings in IB, doesnt make a difference.

    enter image description here

    Is there a correct way to do overcome this, as in make a modal view look like the auto generated nav view.

    Thanks

  • Naveed
    Naveed over 10 years
    I was having the same problem and I used Option 1 from your answer It works great. Have you found another way of some how setting the size of the navbar maybe in interface builder? I was just wondering if embedding something in navigation controller automatically generates that bar with the correct then there might be a way of doing it instead of resizing it in each view controller.
  • DogCoffee
    DogCoffee over 10 years
    @Naveed, havent found a way in IB. I didn't look at your second idea yet.
  • dulgan
    dulgan over 10 years
    Using Autolayout isn't the problem at all here. I think people want to use Autolayout AND solve this issue, so sorry for downvote but your answer is not useful
  • dulgan
    dulgan over 10 years
    I think all this is a bit complicated, just give a shot at what I posted below and give me a feedback if you can. Thanks anyway for your workaround ideas
  • Matt
    Matt over 10 years
    Thanks @CharlieSeligman but seeing that my answer isn't very old, people might have seen it enough especially since it has not been marked as the right one.
  • Anton
    Anton over 10 years
    @Matt saved me a few grey hairs! Thank's a lot.
  • DogCoffee
    DogCoffee about 10 years
    @Matt, good stuff! I changed my answer to yours, this is a clean approach.
  • Matt
    Matt about 10 years
    @Smick I'm happy to have helped. It took me a lot of digging when the iOS7 was launched.
  • Joe C
    Joe C about 9 years
    What do you mean by "You connect the delegate of your NavigationBar to your view controller"? myNavBar.delegate = self doesn't work if you've only conformed to UIBarPositioningDelegate in your ViewController.
  • Matt
    Matt about 9 years
    I have done it both ways. Place the navBar in Storyboard 20 points below and control drag the delegate to the view controller itself from within the storyboard. Or, you could make an outlet and do myNavBar.delegate = self from within the view controller and conform to UIBarPositioningDelegate and implement the method. Are you sure your outlet is connected to the property or if it is created by code you have placed it right?
  • sysuser
    sysuser about 9 years
    Your third solution is working out wonders for me. It solved me two problems 1 - not having the title button close to the battery 2 - Title doesn't disappear when I scroll down the table, I need to do more work otherwise for a standalone navigation bar not embedded in a nav controller.
  • kelin
    kelin almost 9 years
    Assigning to navigationBar.frame has no effect.
  • Sahil Khanna
    Sahil Khanna about 8 years
    I tried option 3 and it worked fine. Option 3 seemingly is a clean option as it avoids writing additional code.
  • Jarrod Smith
    Jarrod Smith about 8 years
    Can you give an example detailing how to declare and assign the delegate? I'm doing class ComposeViewController: UIViewController, UIBarPositioningDelegate and then self.navigationController?.navigationBar.delegate = self. This doesn't compile since UIBarPositioningDelegate does not conform to UINavigationBarDelegate.
  • Gary Johnson
    Gary Johnson about 8 years
    Thanks so much for this. I used a constraint to lock the top of the nav bar to the top layout guide, instead of 20px from the top-level view. Both seem to work when the status bar gets bigger (CMD+Y in simulator). Any downsides to using the top layout guide instead?
  • Matt
    Matt about 8 years
    @GaryJohnson when you add a constraint to the navigation bar placed 20pts below, the constraint you add will be 0pts to top layout guide. It won't be to the superview. So what you did is exactly how you're supposed to do it. As by default on iOS 8 and above the status bar is hidden for landscape phone.
  • rmp
    rmp over 7 years
    This worked for me but just to be clear, and answer @Matt, you need both UINavigationBarDelegate and UIBarPositioningDelegate
  • Matt
    Matt over 7 years
    @rmp That's what I meant by "You connect the delegate of your NavigationBar". The easiest way is through storyboard but you can of course do it in code.