UINavigationController's back button doesn't disappear when UIViewController is popped - ios

I have this UINavigationController that when pushed automatically goes to landscape but can be changeable.
When I pop the view in portrait it goes back to the first/root view normally but when I pop the view in landscape, the back button remains and when I press it, it animates just like when popping a normal navigation controller and the button disappears.
I tried logging the view controllers whenever the main view appears and same with the second view, the logs that I got we're quite normal. On the first view only 1 view controller, and on the pushed view only 2 view controllers.
So, what could be the problem?
I'm not adding any custom buttons at all. It's the standard UINavigationController's back button.
Code:
Pushing the view controller
SomeViewController *rmVC = [[SomeViewController alloc] initWithNibName:#"SomeViewController" bundle:nil];
AppDelegate *ad = (AppDelegate*)[[UIApplication sharedApplication] delegate];
[ad.someNavigationController pushViewController: rmVC animated:YES];
This was done in this way 'cause this was pushed in a presentModalViewController
At someViewController's viewDidLoad
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeLeft];
Pics
http://s1058.photobucket.com/albums/t411/shlbypuerto/

Related

Modal Presentation Forcing Navigation Controller to Pop to Root

I am having a strange problem that I can't seem to find the cause for.
When attempting to present a modal view controller on a navigation controller the navigation controller is popping all of my view controllers underneath when the modal is dismissed.
So after pushing a few view controllers and presenting a modal on the topViewController, I end up back at the rootViewController when the modal is dismissed.
Anyone had this happen to them lately, I can't seem to find the reasoning for why this is happening?
This answer is for #rshev:
It was actually a user error. Here's what was happening: I had a view controller with a manually added navigationController on top of it (as a subview/child VC). The nav controller then had 3 VCs in its stack. The third (and visible) VC was presenting an image picker controller. When the image picker was dismissed, I momentarily saw my third VC , then it quickly popped back to the 1st, discarding the other two VC's from memory.
So what went wrong? What I didn't realize is that viewDidAppear (and viewWillAppear) was being called on my content view controller (the one with nav controller for its subview). This content VC was actually setting its navigation controller (and adding it as a subview) on viewDidAppear, thus covering up the original nav controller.
To solve it, I just added a static boolean to determine when the first VC FIRST appears, like so:
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
static BOOL firstAppearance = YES;
if (firstAppearance)
{
firstAppearance = NO;
UINavigationController *navController = [self.storyboard instantiateViewControllerWithIdentifier:#"NavigationController"];
[navController.view setFrame:self.view.bounds];
[self.view addSubview:navController.view];
[self addChildViewController:navController];
[navController didMoveToParentViewController:self];
}
}
Hope that helps.

Pushing a UITableViewController from a tabBarController embedded view doesn't remove tab bar?

I have a tab bar controller with 4 tabs and each tab is their own UINavigationController, which is how you're supposed to nest tab bar and navigation controller's together. The initial tab is a TableViewController and works/appears the way that it should. From the tableVC I can push standard view controller's onto the navigation controller with:
[self.navigationController pushViewController:VC animated:YES];
and it works properly.
If I attempt to push another TableViewController onto the navigation with the same method it works the same way, but the initial tab bar does not get pushed off screen like it should, it just stays in place.
Why would the tab bar stay on screen even though I am pushing a new VC onto the navigation?
I have tested with multiple instances of different TableVC's and it only happens with a table view controller.
Here is the code I'm using:
- (void)pushTableVC
{
TestTableVC *tableVC = [[TestTableVC alloc] init];
[self.navigationController pushViewController:tableVC animated:YES];
}
This will push the new table view onto the stack, but the tab bar from the parent VC stays in place and does not get pushed off screen like it should.
You should call the method setHidesBottomBarWhenPushed: on the view controller you are pushing to correctly hide the tab bar.
UIViewController *viewController = [[UIViewController alloc] init];
[viewController setHidesBottomBarWhenPushed:YES];
[[self navigationController] pushViewController:viewController animated:YES];
When you use a UITabBarController, the tab bar always stays on screen, even as you push additional view controllers onto an embedded UINavigationController. You will see this in any app that has a UITabBarController implemented, unless they implement custom behavior to change this.
The UINavigationController contains everything above the UITabBar, but does not contain the UITabBar itself, so it would not be able to push it offscreen.

iOS push current view controller onto another view controller hierarchy

I have a view controller (which is the root view of the main UINavigationController for my app) that is presenting another view controller hierarchy modally, by presenting a UINavigationController. After the user interacts with the root view controller in the modal NavController, a detail VC is pushed onto the modal NavController's stack. After some interaction with this detail VC, I'd like to push this detail VC back onto the original hierarchy, and dismiss the modal NavController/it's root view controller, all without the user seeing the change in this hierarchy. Right now I have something like this:
In MyViewController1 (root of the main NavController hierarchy):
UINavigationController *newModalNavController = [[UINavigationController alloc]
initWithRootViewController:someRootViewController];
[self presentViewController:newModalNavController animated:YES completion:nil];
Then in the someRootViewController above, after some interaction (e.g. a button click), I push the detail view controller onto the modal hierarchy:
[self.navigationController pushViewController:detailVC animated:YES];
Finally, in the detailVC, after some more interaction:
UINavigationController *mainNavController = /* Get main nav controller here (i.e. non-modal one) */
// Dismisses the modal view hierarchy (detailVC gets -(void)viewDidDisappear)
[self.presentingViewController dismissViewControllerAnimated:NO completion:nil];
// Repush the detailVC back onto the main hierarchy (detailVC gets -(void)viewDidAppear)
[mainNavController pushViewController:self animated:NO];
// Keyboard was on screen before interaction; make it stay on screen after pushing
// detailVC onto main nav hierarchy
[self.textView becomeFirstResponder];
This all works (clicking back on the detailVC's navigationItem after pushing it onto the mainNavController's hierarchy goes back to the original rootViewController, MyViewController1), except when the keyboard is on screen in the detail view controller as it is being switched, it gets hidden and then animates back up, instead of just staying on screen (because the view is disappearing for a second as the presentingViewController dismisses the modal nav controller, whose hierarchy the detailVC is a part of, and then reappears as it gets pushed onto the mainNavController's stack, and the textView grabs first responder again).
Is there a better way to change which navigation hierarchy the detail view controller is a part of, possibly one that doesn't involve the view disappearing, and thus the keyboard being hidden and immediately reshown?

Back to RootViewController from Modal View Controller

From Home view - my RootViewController - I open up 2 ViewControllers one after another as user progresses in navigation hierarchy like so:
1) SecondViewController is pushed by button connected in my Storyboard
2) ThirdViewController is presented modally
[self performSegueWithIdentifier:#"NextViewController" sender:nil];
So, the picture is: RootViewController -> SecondViewController -> ThirdViewController
Now in my ThirdViewController I want to have a button to go back 2 times to my RootViewController, i.e. go home. But this does not work:
[self.navigationController popToRootViewControllerAnimated:YES];
Only this guy goes back once to SecondViewController
[self.navigationController popViewControllerAnimated:YES];
How can I remove both modal and pushed view controllers at the same time?
I had a similar situation, where I had a number of view controllers pushed onto the navigation controller stack, and then the last view was presented modally. On the modal screen, I have a Cancel button that goes back to the root view controller.
In the modal view controller, I have an action that is triggered when the Cancel button is tapped:
- (IBAction)cancel:(id)sender
{
[self.delegate modalViewControllerDidCancel];
}
In the header of this modal view controller, I declare a protocol:
#protocol ModalViewControllerDelegate
- (void)modalViewControllerDidCancel;
#end
And then the last view controller in the navigation stack (the one that presented the modal view) should implement the ModalViewControllerDelegate protocol:
- (void)modalViewControllerDidCancel
{
[self dismissViewControllerAnimated:NO completion:nil];
[self.navigationController popToRootViewControllerAnimated:YES];
}
This method above is the important part. It gets the presenting view controller to dismiss the modal view, and then it pops back to the root view controller. Note that I pass NO to dismissViewControllerAnimated: and YES to popToRootViewControllerAnimated: to get a smoother animation from modal view to root view.
I had the same requirement but was using custom segues between the view controllers. I came across with the concept of "Unwind Segue" which I think came with iOS6. If you are targeting iOS6 and above these links might help:
What are Unwind segues for and how do you use them?
http://chrisrisner.com/Unwinding-with-iOS-and-Storyboards
Thanks.
Assuming your AppDelegate is called AppDelegate, then you can do the following which will reset the rootviewcontroller for the app window as the view RootViewController
AppDelegate *appDel = (AppDelegate*)[[UIApplication sharedApplication] delegate];
RootViewController *rootView = [[RootViewController alloc] init];
[appDel.window setRootViewController:rootView];

Switching between sibling views via UINavigationViewController

I am using a NavigationViewController to navigate between master view and detailed views. Now I want to be able to switch to a sibling detail view without first showing the master view and I have tried doing popViewController and pushViewController in the same method or popViewController in the detailed view and then pushViewController in mater's viewDidLoad after popViewController but it won't work - the view just ends up going back to the master view without switching to the detail. Any idea what to do?
The solution suggested here doesn't work as far as I can tell:
Switching Content Views Issue
I've never tried it, but this should work:
// create instance of new view controller
MyViewController *myViewController = [[MyViewController alloc] init];
// get current stack of viewControllers from navigation controller
NSMutableArray *viewControllers = [[self.navigationController viewControllers] mutableCopy];
// replace top view controller in stack
[viewControllers replaceObjectAtIndex:([viewControllers count] - 1) withObject:myViewController];
// set modified stack of view controllers in navigation controller
[self.navigationController setViewControllers:viewControllers animated:YES];
According to the docs, your app will transition to the new view controller with a push animation, and then when back button is clicked it it will be as if the view controller you pushed from was never there. (If you don't want the animation, use animated:NO)

Resources