17

I have view controllers in a navigation controller (root: RootViewController, second: ReadingViewController), but in the second view controller I want to disable the navigation bar for a UIToolBar (as I don't need the title and want more buttons, like in iBooks or the Facebook app). Problem is, when I hide the navigation bar in the second view, it appears randomly for a second again when I pop the view controller (go back).

When I pop the view controller the back button appears for a second:

enter image description here

In the second view controller I hide the nav bar in viewWillAppear::

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    [self.navigationController setNavigationBarHidden:YES animated:YES];
}

Also in the second view controller, I restore the nav bar in viewWillDisappear::

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];

    // ... other stuff

    [self.navigationController setNavigationBarHidden:NO animated:YES];
}

I'm wondering how I combat this issue so that the view controllers transition seamlessly.

Nishant Tyagi
  • 9,893
  • 3
  • 40
  • 61
Doug Smith
  • 29,668
  • 57
  • 204
  • 388
  • Show the code, names of the view controller, etc. What are you actually doing? – matt Apr 28 '13 at 21:27
  • Added, if I missed anything please just ask. – Doug Smith Apr 30 '13 at 21:12
  • I am unable to reproduce the problem. Look, I made you a video! http://youtu.be/PxpchytWQ4A To me, that's as coherent as you are going to get when showing and hiding the nav bar as you push and pop. – matt Apr 30 '13 at 21:47
  • Could you share your project? – Doug Smith Apr 30 '13 at 22:27
  • Edit my answer to show the code I used. Pretty simple. But really, I suspect that the problem here is that you are doing something *else* you're not describing. The thing to do in cases like this is to make a minimal project that concentrates on just the problem at hand (as I did). That way, you convince yourself that this *can* work. Then you can worry about what *else* you are doing that is *preventing* it from working. – matt Apr 30 '13 at 22:49
  • 3
    Out of curiosity, have you considered keeping the navigation bar in place and using the new ```[UINavigationItem leftBarButtonItems]``` and ```[UINavigationItem rightBarButtonItems]``` APIs? – Ell Neal May 06 '13 at 02:04
  • In the first view controller viewWillAppear try setting [self.navigationController setNavigationBarHidden:NO animated:NO]; – Xcoder May 07 '13 at 05:58
  • @DougSmith Check The Answer That I have posted. – Ayush May 21 '13 at 15:00

8 Answers8

15

The problem here is that viewDidLoad is way too soon! Remember, viewDidLoad does not have anything to do with the interface and the actual push animation. It does not mean that this view controller's view is about to appear on screen! It merely means that the view controller has obtained its view.

I made a video, showing what happens on my machine as I move back and forth between two view controllers in a navigation interface, one of which shows the navigation bar, the other does not: http://youtu.be/PxpchytWQ4A

To me, that's as coherent as you are going to get when showing and hiding the nav bar as you push and pop! Here's the code I used. The view controller that hides its nav bar is of class ViewController2. This code is in the app delegate:

- (BOOL)application:(UIApplication *)application 
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    dispatch_async(dispatch_get_main_queue(), ^{
        [(UINavigationController*)self.window.rootViewController setDelegate:self];
    });
    return YES;
}

-(void)navigationController:(UINavigationController *)nc 
     willShowViewController:(UIViewController *)vc 
                   animated:(BOOL)animated 
{
    [nc setNavigationBarHidden:([vc isKindOfClass:[ViewController2 class]]) 
                      animated:animated];   
}

That's all I did.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • If I do it in viewWillAppear, it is there for a second, gets removed, and then the UIToolBar "falls down" when it gets removed. – Doug Smith Apr 28 '13 at 21:53
  • Might try `viewDidAppear`. I notice you still have not shown any code as I asked. This is all sheer folly and guesswork if you don't actually show exactly what you are doing. – matt Apr 28 '13 at 21:55
  • It did not work in viewDidAppear, but I added what you requested, and if I missed anything, please just say. – Doug Smith Apr 30 '13 at 21:13
  • I modified my answer to give a solution that works for me. I don't know why your code isn't working for you. – matt Apr 30 '13 at 23:13
  • Is it anything I could be doing in my storyboard? – Doug Smith May 01 '13 at 02:26
  • How should I know? My project uses a storyboard and I'm not seeing the issue. Since I can't reproduce your problem, I can't help further. But I do think I've proved that whatever glitch it is you're seeing doesn't *have* to happen when the nav bar shows and hides during the push/pop transition. – matt May 01 '13 at 02:42
  • I did find this, there's a nav back item that I cannot remove: http://i.imgur.com/MAa2kHA.png – Doug Smith May 05 '13 at 19:50
  • The back item belongs to the previous view controller. – matt May 05 '13 at 22:50
  • Don't hide navigation bar with animation, I think that's the issue. You can either use some kind of delayed animation *after* the view controller is pushed and its view did appear, or you can modify UI layout without animation - in that case it should work correctly. – art-divin May 06 '13 at 08:37
  • @art-divin it works fine in my movie (see my answer) and I do show and hide the nav bar with animation. In fact it looks bad without it. – matt May 06 '13 at 13:04
  • @matt your implementation is different from the author's, I was pointing out author's error and workaround that might work. Your is working because the dispatch of this methods is fine to use with animation. By the way, dispatch_get_main_queue() is redundant in -appDidFinishLaunchingWithOptions because this method is always called on the main thread – art-divin May 06 '13 at 13:12
  • @art-divin (1) The OP's code should work. The cause of the ghost nav bar is unclear; there is stuff going on that the OP has never told us about. (2) It isn't redundant. It's delayed performance to guarantee the references. – matt May 06 '13 at 14:21
  • @matt, thanks a lot! setNavigationBarHidden while push animation works not well in iOS 8.2, so your solution saved my life :) But better to replace this code in view controller, when you wanna hide nav bar, IMHO – aquarium_moose Apr 08 '15 at 14:34
  • @matt This fixes the problem for us too: interestingly the flickering is not even contained tot he nav bar for us, the whole view flickers. With your approach (willShowViewController), everything works. – xaphod Jul 21 '15 at 13:11
  • Thanks a million! It works perfect for me. This is my swift version - class NavigationControllerDelegate: NSObject, UINavigationControllerDelegate { static let shared = NavigationControllerDelegate() func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) { navigationController.setNavigationBarHidden(viewController is VCWithNavBar, animated: animated) } } – Kamen Dobrev Oct 21 '20 at 09:43
2

Hey why don't you use navigation bar as a UIToolbar.

Instead Of hiding UINavigation you can mimic navigation controller to UITootlbar by adding buttons to it.

hiding unhiding UINavigation would be complex.

I am Uploaded the dropbox link.

Ayush
  • 3,989
  • 1
  • 26
  • 34
  • 2
    This is interesting idea and I would try to do it exactly this way. Instead of using `leftBarButtonItem` try to use `leftBarButtonItems` (notice the “s” at the end, it's an array of items). This way you can have as many items in navigation bar as you want. You can see example of usage in Pages.app. – Tricertops May 24 '13 at 06:19
1

In the second view controller hide the nav bar in viewWillAppear::

self.navigationController.navigationBar.frame = CGRectMake(0, 0, 0, 0);

For unhiding the navigation bar set the frame in viewWillDisappear:

self.navigationController.navigationBar.frame = CGRectMake(0, 0, 320, 44);
ronalchn
  • 12,225
  • 10
  • 51
  • 61
Malathi
  • 47
  • 5
  • That causes a black bar to appear where the navigation bar used to be: http://i.imgur.com/YQdjNCS.png – Doug Smith May 05 '13 at 19:28
  • Move subviews on secondViewController to up i.e change y position of subviews – Malathi May 06 '13 at 10:57
  • 3
    Please, for your own safety and everyone else's don't start mucking around directly with the frame of `self.navigationController.navigationBar` and hard coded magic numbers. – Mike Pollard May 22 '13 at 08:58
1

Well, as I understand from your question the only problem of your current approach is temporary appearance of original "Back" button. So why not just block this button for the view controller?

self.navigationItem.hidesBackButton = YES;

I think it might help. But for your main task I'd rather suggest you to use custom navigation bar with ability to add as many buttons as you want. Such approach is more natural for iOS and you'll probably never face the issues like you mentioned in your question.

Andrei Chevozerov
  • 1,029
  • 1
  • 10
  • 24
0

Hello The following stuff done my job

In FirstViewController put this method

- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    [self.navigationController setNavigationBarHidden:NO animated:YES];
}

and in SecondViewController put this method

- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];

    [self.navigationController setNavigationBarHidden:YES animated:YES];
}

I have not used viewWillDisappear for my work done.

Hope will help you.

Yuvrajsinh
  • 4,536
  • 1
  • 18
  • 32
0

It could be as simple as moving your code from viewWillDisappear to viewDidDisappear.

Also, avoid using animations in any view*appear methods, as the view-transition is already being animated.

patric.schenke
  • 942
  • 11
  • 19
0

MY problem is that when I push a viewController with a navigationBar onto one without it by using a customised transition moving it from the left side, I am not able to have it follow the second view controller's frame. It always drops from above producing a very unpleasant effect whenever I perform this action.

user1785898
  • 167
  • 1
  • 1
  • 7
0

You can show the navigation bar, which makes it appear in your parent view controller, and then transition the alpha from 0 to 1:

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];

    self.navigationController.navigationBar.hidden = NO;
    self.navigationController.navigationBar.alpha = 0;

    [UIView animateWithDuration:0.3 animations:^{
        self.navigationController.navigationBar.alpha = 1;
    }];
}
therin
  • 1,448
  • 1
  • 15
  • 27