views:

787

answers:

3

I am using a UINavigationController (side note: inside a UITabBar) which by default gives you a UINavigationBar on the top. If I hide the bar through IB, the bar is gone not only for the root UIViewController but also for all the controllers I push onto the stack. Leaving me no (automatic) way to pop back.

So how can hide the UINavigtionBar only on the root UIViewController. Switching on/off "navigationBarHidden" temporarily does not work as this looks awkward with the animation.

Any other ideas?

A: 

My idea would be to not make your first view part of the navigation controller. Have a simple TableViewController, for instance, and then when you want to drill down, create the UINavigationController, and push it's view in manually.

I haven't tried this and don't know whether it'll work, though. Just an idea to try.

Thomas Müller
Unfortunately that does not work because the root controller does not have a back button.
tcurdt
I am wondering if I could just do this and *add* a button on the left to the UINavigationBar. Will have to try (although I went a different route instead for now)
tcurdt
A: 

You have a couple of different nasty ways you can do it. The fact that you are embedded in a UITAbBar controller actually significantly complicates this because there is no way to distinquish whether viewDidAppear: is called due to the controller being pushed or from tab swapping, meaning you may need to stash data somewhere in order to know what is causing the transition and whether you need to hide the bar or not.

Assuming you handle that, one option is to change navigationBarHidden after you have animated in. On the way out there is no good place to handle that since you want the pop animation to happen after the bar animates. The quickest solution is to hide the bar then manually run your runloop for ~0.5 seconds until it animates out then continue. Its gross but it is quick and it works.

- (void)viewWillDisappear:(BOOL)animated {
  if (animated) {
     [self.navigationController.navigationBar setHidden:YES animated:YES];
  }

  //GROSS
  NSDate *endDate = [NSDate dateWithTimeIntervalSinceNow:0.5];
  while([[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:endDate]);
}

If you want to do it cleanly, I recommend reimplementing UINavigationController from scratch.

Louis Gerbarg
You dont need to implement anything from scratch, simply subclass UINavigationController will sufice, check out my answer.
Daniel
You can do that, but depending on what you are doing you will get lots of problematic interactions with the other animations UINavigationController is scheduling because all of them will be commited at the same time and you have no control over them. I have done it that way in the past, but as soon as I wanted to do anything else (like custom transitions) it falls apart, and it is totally dependent on the internal timing of how UINavigaitionController schedules its animations.
Louis Gerbarg
+2  A: 

I actually ran into this problem, how i solved it was with the UINavigationCOntroller delegate, i basically have a UINavigationController subclass and made it its own delegate, then i implemented the method - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated of the protocol to look something like this

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    if([viewController isKindOfClass:[SomeClass class])
     [self setNavigationBarHidden:NO]
    else
  [self setNavigationBarHidden:YES]



}

So you ask which class it is and if its one that needs to have a navigationBar you show it, this worked for me pretty well...hope it helps

Daniel
That's what I tried, too. But that will let the bar just appear on the screen and not just on the view that gets animated in. Certainly should be fine without an animation. But I want the animation.
tcurdt
?? what do you mean? Its on the s creen there sure, but it only appears when you push the view you need, even if its animated...whats the issue?
Daniel
If you dont want that animation of the bar itself you can write the same code in the – navigationController:didShowViewController:animated: method instead, that way it appears only after the view is pushed..
Daniel
The problem is that the animation is not sequenced correctly if you do that. The par will move simultaneously with the push/pop and in some cases will glitch with a bunch of white space because the exact details of how the builtin animations are running. That is why I did the whole runloop hack in my response.
Louis Gerbarg
didnt expirience this, you got some screen shots?
Daniel
Daniel, the problem is that usually the view just animates in. Using your approach gives another animation: the navigation bar hiding/showing ...which is not desired.But anyway. I think you probably got closest to the answer. So I'll accept yours.
tcurdt