Navigation Bar set to be invisible, but when back button is clicked it appears - objective-c

As the title indicates, the root view is my navigation controller, and it is set to be invisible, which it is on launch. However if I push a view onto the stack and then pop it the navigation bar appears.
Any clues as to why and how to remedy the situation?

You need to hide it every time yours controller's view appears (or disappears) on screen. This is necessary since the bar maintains the state among differents push/pop operations. For example, if you have set it hidden in viewDidLoad within in first controller and in the second one you set it visible, when you pop the second controller the bar mantains the last state you have set.
For example override viewWillAppear and viewWillDisappear methods and hide/unhide the bar there.
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:animated];
}
- (void) viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.navigationController setNavigationBarHidden:NO animated:animated];
}

Related

Is there a way to remove UITabBar/or do something for a UIViewController and ALL other UIViewcontroller added on top of UINavigationBar Stack?

This is the approach I am using:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.tabBarController hideTabBar];
}
-(void) viewWillDisappear:(BOOL)animated
{
[self.tabBarController showTabBar];
[super viewWillDisappear:animated];
}
With this approach if I add something to the navigation stack the UITabBar will be shown again.
What about if I want UITabBar to be only shown when user navigate away to another tab or press back button, so not all cases of viewWillDisappear?
Pushing a UIViewController on top of navigation stack shouldn't change that
You can use NSNotification as well, so whenever you require to hide tab bar. At that moment fire that notification which will show/hide your tab bar.
Benifit of NSNotification is, you can fire that in entire application life cycle, and it does not be specific to any view controller or any class. One can use that independently from any class/view controller.
Hope this is what you are looking for.
Regards,
Mrunal
Do following in your view will appear method
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillDisappear:animated];
self.navigationController.tabBarController.tabBarController.tabBar.hidden=TRUE;
}
This will remove tabbar from the particular controller . and navigation stack will not change.
This is what I did
At viewDidDisappear, I check if self.navigationController is empty. If it's empty I simply know that the view has been poped out of navigationController, which is the only way to get that view out of window hierarchy.

Should I use the same detail ViewController to work both modally and when pushed?

This seems to be the patten used throughout Apples applications; Creation of a new record is done through a modal View which needs to be saved or canceled to continue, and editing a record is done through a view pushed onto the navigation stack.
It doesn't seem right to be basically duplicating my ViewController for 'add' and 'edit' but there are several differences in how pushed and modal ViewControllers work which complicate things.
How should I be doing this so it can cover both bases?
-
Differences include.
When pushed onto the stack the navBar appears at the top of the View and can be configured to contain the cancel/save buttons. When presented modally this is not the case so to duplicate the interface a toolbar needs to be created separately and close/save buttons added to this instead.
When dismissing a pushed view we send a message to the navigation controller [self.navigationController popViewControllerAnimated:YES];, when dismissing a modal view we send a message to self [self dismissModalViewControllerAnimated:YES];
You could add the UIToolbar in InterfaceBuilder, and then just hide it in viewDidLoad when self.navigationController is not nil.
As for dismissing, you could have something like:
- (void)didCancel {
[self.navigationController popViewControllerAnimated:YES] || [self dismissModalViewControllerAnimated:YES];
}
This will shortcircuit if your viewcontroller is part of a navigationcontrol, and use dismissModalViewControllerAnimated otherwise.
This should work for your cancel button. For your save button, it is useful to call some sort of delegate method such as:
- (void)didSave {
// do your saving juju here
if([self.delegate respondsToSelector:#selector(viewController:didSave:]) {
[self.delegate viewController:self didSave:whatJustGotSaved];
}
[self.navigationController popViewControllerAnimated:YES]; // noop if currently modal
}
In the delegate's implementation then, you can put:
- (void)viewController:(UIViewController*)viewController didSave:(NSObject*)whatJustGotSaved {
// do stuff with parameters
[self.modalViewController dismissModalViewControllerAnimated:YES]; // noop if not modal
}

popToRootViewControllerAnimated does not display root view controller

I need a little help on a problem with navigation controllers.
I have a navigationController with 4 ViewControllers pushed. The last vc I push presents a further ViewController modally. The modal ViewController presents an ActionSheet. Depending on the user's answer I either dismiss the modal ViewController only or I want to go back to the root ViewController.
In the ViewController presented modally I have:
- (void) dismissGameReport
{
[[self delegate] GameReportModalWillBeDismissed:modalToPopToRoot];
}
In the last ViewController pushed onto the navigationController stack I have:
- (void)GameReportModalWillBeDismissed: (BOOL)popToRoot;
{
if (popToRoot)
{
[self.navigationController popToRootViewControllerAnimated:NO];
}
else
{
[self dismissModalViewControllerAnimated:YES];
}
}
Dismissing the modal view controller works fine.
However,
[self.navigationController popToRootViewControllerAnimated:NO];
does not cause the root ViewController to display its views. Adding some log info I see that after the message to self.navigationController the stack is correctly popped but execution continues sequentially. The screen still shows the view of the modal ViewController.
As a workaround I tried always dismissing the modal view controller and in the ViewWillAppear method have the popToRootAnimated message. No difference. Still the stack of controllers is popped but the screen continues showing my modal view controller's view and execution continues sequentially.
Could someone help me please?
I like these deceptive questions. It seems very simple, until you try to do it.
What I found was that basically you do need to dismiss that modal view controller, but if you try to pop from the navigation controller on the next line things get mixed up. You must ensure the dismiss is complete before attempting the pop. In iOS 5 you can use dismissViewControllerAnimated:completion: like so.
-(void)GameReportModalWillBeDismissed:(BOOL)popToRoot{
if (popToRoot){
[self dismissViewControllerAnimated:YES completion:^{
[self.navigationController popToRootViewControllerAnimated:YES];
}];
}
else{
[self dismissModalViewControllerAnimated:YES];
}
}
But I see you have 4.0 in your question tags. The solution I found for <iOS 5 is far less pretty but should still work, and it sounds like you were already on the trail. You want viewDidAppear: not viewWillAppear:. My solution here involves an ivar, lets say:
BOOL shouldPopToRootOnAppear;
And then your GameReportModalWillBeDismissed: would look something like this:
-(void)GameReportModalWillBeDismissed:(BOOL)popToRoot{
shouldPopToRootOnAppear = popToRoot;
[self dismissModalViewControllerAnimated:YES];
}
And your viewDidAppear: would look like this...
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
if (shouldPopToRootOnAppear){
[self.navigationController popToRootViewControllerAnimated:YES];
return;
}
// Normal viewDidAppear: stuff here
}

How to push UIViewController with Nav while inside View Controller without nav bar

I'm showing UINavigationController modally.
For the root view controller, I don't want to show the Navigation bar.
However for deeper controllers, I do want to show it.
I though of doing something like this inside my root view controller :
-(void) viewWillAppear:(BOOL)animated
{
[self.navigationController.navigationBar setHidden:YES];
}
-(void) viewWillDisappear:(BOOL)animated
{
[self.navigationController.navigationBar setHidden:NO];
}
However, this presents issues, when I go back from the first view controller to the root view controller.
The navigation bar is disappearing after pressing the "back" button (inside the first view controller, leaving white space), and not only after the rootViewController finished loading. (Obviously because my code uses viewWillAppear)
Is there a solution for it ?
The only thing I thought of is hidiing the navigation bar permanently, and adding Navigation bar manually to each view controller in the stack.
I hope not to do that since it's much more work, and moreover, I want to use arrow shaped buttons, for which I would have to create custom images.
Appreciate any suggestions.
This should do it, I haven't tested it out, but should work in theory:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:YES];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.navigationController setNavigationBarHidden:NO animated:YES];
}

UIViewController to know if it got pushed or popped?

I have a main UITableView, when cell is pressed it goes to another UITableView and when a cell is pressed there it goes to a DetailView of that cell.
I want the middle UITableView to behave differently depending on if the detailView got popped or the UITableView itself got pushed. If the view got pushed on from the main table I want to scroll to the top, if it is shown after a DetailView got popped I want it to stay at the same position.
Any suggestions?
you could call a scrollToTop method on the DetailViewController after you have pushed it to the navigationController.
Something like that:
if (!detailViewController) {
detailViewController = [[DetailViewController alloc] initWithNibName:nil bundle:nil];
}
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController scrollToTop];
// or use the tableView directly:
// [detailViewController.tableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0] atScrollPosition:UITableViewScrollPositionTop animated:YES];
In your Middle View Controller, examine which view is next-to-display directly from the UINavigationController stack:
- (void)viewWillDisappear:(BOOL)animated
{
if ([self.navigationController.topViewController isEqual:(UITableViewController *)tvcDetailView]) {
// Detail view has been pushed onto the UINavigationController stack
}
else {
// Middle view has been popped from the UINavigationController stack
}
}
Create a BOOL #property on your middle UIViewController property called wasPushed or something similar, and when you initialise it from UIViewController 1, set the property on the new instance, push it onto the nav stack and you can then use your property in your middle view controller's loadView, viewDidLoad, viewWill/DidAppear methods.
As soon as you've used it, set it back to FALSE or NO (or whatever) and when you end up coming back to it due to popping off your 3rd view controller you'll have it as FALSE/NO in your loadView, viewDidLoad etc.. methods.