Navigation Controller from a View Controller - ios

I'm using .xib files in an app. And I want to have two view controllers normal way and from the third view controller, embed it in a navigation view controller. Here's an illustration of how I want it.
I know I can embed a navigation controller in a modally presented view controller like this.
let firstVC = FirstViewController(nibName: firstViewController, bundle: nil)
let navController = UINavigationController(rootViewController: firstVC)
presentViewController(navController, animated: true, completion: nil)
But if I embed it in a navigation controller and push it, the app crashes with the error Pushing the same view controller instance more than once is not supported.
let firstVC = FirstViewController(nibName: firstViewController, bundle: nil)
let navController = UINavigationController(rootViewController: firstVC)
navController.pushViewController(firstVC, animated: true)
Is it possible to do this at all? If so, can someone please explain how?
Thank you.
NOTE: Don't confuse the code snippets with the diagram above. The firstViewController in the code is not the first view controller in the diagram.

Suppose that FirstViewcontroller,Secondviewcontroller,Thirdviewcontroller are the three view controllers. then the transition from second to third view controller use the code given below.
Secondviewcontroller *second=[[Secondviewcontroller alloc]init];
UINavigationController *nav=[[UINavigationController alloc]initWithRootViewController: second];
[self presentViewController:nav animated:NO completion:nil];

use the first view controller as the root view controller of the UINavigationController
use the following method to present your next view controller
[self.navigationController pushViewController:vc animated: YES];
in the viewWillAppear method, if you wanna hide the navigation bar, use
[self.navigationController setNavigationBarHidden:YES animated:animated];
If you wanna show the navigation bar, use
[self.navigationController setNavigationBarHidden:NO animated:animated];

Related

Navigation present to another navigation, how to get back to the root navigation

My root navigation has a StoreDetailsController,and I am in the StoreDetailsController present to the ShoppingBagNavigationController.They can be infinite present. What should I do when I want to go back to the root navigation?
- (void)goBagVC{
UINavigationController *shoppingBag = [[UIStoryboard storyboardWithName:#"ShoppingBag" bundle:nil] instantiateViewControllerWithIdentifier:#"ShoppingBagNavigationController"];
ShoppingBagViewController *myshopVC = shoppingBag.viewControllers[0];
[myshopVC passDetailProduct:self.productDetailModel.productID];
[self presentViewController:shoppingBag animated:YES completion:nil];}
- (void)goRootVC{
[self.navigationController.tabBarController setSelectedIndex:0];
[self.navigationController popToRootViewControllerAnimated:YES];}
I want to go root Controller in goRootVC function. Thanks
As ShoppingBagViewController would be your topmost view after you present it, adding a call dismiss(animated: true, completion: nil) to a button press in ShoppingBagViewController would dismiss that screen.
The StoreDetailsController should be visible once the other screen has been dismissed.
It looks to me like you're confusing modal presentation and pushing onto a navigation stack. Your goBagVC method is modally presenting a navigation controller on top of the current view controller. If you want to push view controllers onto a navigation stack then you need to start with a navigation controller and call pushViewController:animated:
You have to search that view controller in yout navigation controller and then pop to that controller.
Swift
let vc = self.navigationController!.viewControllers.filter { $0 is StoreDetailsController }.first!
self.navigationController!.popToViewController(vc, animated: true)

PresentViewController from a presentedViewController is not showing navigation bar

I have three view controllers (vc1, vc2, vc3) and two navigation controllers (nav1, nav2).
nav1 is the entry point of the storyboard.
vc1 is the rootViewController of nav1.
vc2 is the rootViewController of nav2.
nav2 is presented from vc1 through nav1.
Now when I tried to present vc3 from vc2 through nav2, navigation bar is not showing.
You need to present your controller with navigationController.
ViewController *objVC = [self.storyboard instantiateViewControllerWithIdentifier:#"viewcontrollerid"];
UINavigationController *navController = [[UINavigationController alloc]initWithRootViewController:objVC];
[self.navigationController presentViewController:navController animated:YES completion:nil];
Now, the way iOS works, it will never give you an instance of your navigation controller in a presented view controller because when you present a view controller, it is not added to the viewcontroller stack of the navigation controller.
The reason you can see the navigation controller in the other two is because your'e presenting the navigation controller itself and not view controller.

ViewControllers overlapping each other in Main.Storyboard

I've two ViewControllers in Main.Storyboard, entry point ViewController have green background, and another is red background. At the button click of first ViewController it should show second ViewController, but the first and second ViewControllers are overlapping each other and both ViewControllers Buttons are clickable.
Ist view controller (green), bingo is the UIButton
2nd view controller (red), hello is the UIButton
On the click event of the button in first view controller is :
MViewController *mvc = [self.storyboard instantiateViewControllerWithIdentifier:#"mvc"];
[self presentViewController:mvc animated:YES completion:nil];
Try this if its a push segue :
MViewController *mvc = [self.storyboard instantiateViewControllerWithIdentifier:#"mvc"];
[self.navigationController pushViewController:mvc animated:YES];
And you should take one navigation controller and assign it as initial view and make green view the root view. Delete the default root view controller comes with it.
You can write this code in the action block of bingo button
{
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let redVC = storyBoard.instantiateViewControllerWithIdentifier("**RedViewControllerSID**") as RedViewController
self.presentViewController(redVC, animated:true, completion:nil)
}
go storyboard and create Storyboard ID as RedViewControllerSID

Present multiple modal view controllers?

update:
I've faced this problem again, and found another way. If presenting controller is not embedded in navigation controller, it will be hidden if presented controller is not fullscreen and will became black. Method setModalPresentationStyle:UIModalPresentationCurrentContext can be applied only to navigation controller. So embed presenting controller in UINavigationController, set UIModalPresentationCurrentContext to it and present new controller - you will get dialog controller.
I'm presenting search controller, it have tableView that push on stack detailed controller.
Detailed controller can present view controller with message, it consists from small UIView and semitransparent background.
Problem: when last view controller presented, all view controllers under it becomes hidden and controller, that presented search controller becomes visible.
Here what I'm doing:
SearchViewController *viewController = [[SearchViewController alloc] initWithNibName:#"SearchViewController" bundle:nil];
viewController.data = dataArray;
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
[self.navigationController setModalPresentationStyle:UIModalPresentationCurrentContext];
[self.navigationController presentViewController:navigationController animated:YES completion:nil];
than table pushes detailed view:
DetailViewController *viewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController" bundle:nil];
[viewController setHidesBottomBarWhenPushed:YES];
viewController.dataItem = [data objectAtIndex:(NSUInteger) [indexPath row]];
[self.navigationController pushViewController:viewController animated:YES];
and detailed view presenting message box:
MessageController *controller = [[MessageController alloc] initWithNibName:#"MessageController" bundle:nil];
controller.message = message;
[self presentViewController:controller animated:YES completion:nil];
When it's dismissed, all controllers under it became visible.
update:
all I wanted is to present modally a view controller that will have uitableview. From this table to show detailed view that will be able to show message box. Message box must be another view controller. And when message box is shown all two preceding controllers disappears. that is the issue.
In some situations, you could have each modally presented view controller present the next one.
let window = UIApplication.sharedApplication().keyWindow!
if let modalVC = window.rootViewController?.presentedViewController {
modalVC.presentViewController(vc, animated: true, completion: nil)
} else {
window.rootViewController!.presentViewController(vc, animated: true, completion: nil)
}
Dismiss all view controllers above the presented view controller.
Apple's documentation follows:
If you present several view controllers in succession, thus building a stack of presented view controllers, calling this method on a view controller lower in the stack dismisses its immediate child view controller and all view controllers above that child on the stack. When this happens, only the top-most view is dismissed in an animated fashion; any intermediate view controllers are simply removed from the stack. The top-most view is dismissed using its modal transition style, which may differ from the styles used by other view controllers lower in the stack.
Dismiss two modal view controllers.
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:NULL];
https://developer.apple.com/library/ios/documentation/uikit/reference/UIViewController_Class/Reference/Reference.html#jumpTo_51
This answer might seem a little unconventional, but it works. It lets you "open multiple modals", but only show one at a time. The key is to have just one modal, but use a Tab Bar Controller to switch between View Controllers.
Wire your modal segue from the blue (presenting) View Controller to a modal container (which is just a regular View Controller)
The modal container holds just a Container View, whose sole purpose is to embed a Tab Bar Controller.
Embed a Tab Bar Controller inside the Container View
Each tab can be a separate View Controller, representing "multiple modals"
Set the Tab Bar Controller's Tab Bar to hidden
Switch between modals using tabBarController?.selectedIndex = 1
Close the modal normally with dismissViewControllerAnimated(true, completion: nil)
It would look something like this:
The trivial way to attempt to achieve that is to just create the VCs
you want to present modally and present one after the other.
Unfortunately, this is not gonna work. What you get is just the first
VC presented, all others just go nowhere. UIKit just won’t cooperate
with you here.
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
[self.view.layer renderInContext:context];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
Set the correct modalPresentationStyle on both the navigationController AND the viewController itself.
self.navigationController.modalPresentationStyle = UIModalPresentationCurrentContext;
vcToPresent.modalPresentationStyle = UIModalPresentationFormSheet;
vcToPresent.preferredContentSize = CGSizeMake(650, 450);
[self presentViewController:vcToPresent animated:YES completion:^{
self.navigationController.modalPresentationStyle = UIModalPresentationFormSheet;
}];`
I found a solution: provide your own custom animation:
let transition: CATransition = CATransition()
transition.duration = 0.5
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.type = kCATransitionReveal
transition.subtype = kCATransitionFromBottom
self.view.window!.layer.add(transition, forKey: nil)
self.presentingViewController?.presentingViewController?.dismiss(animated: false, completion: nil)

'Push segues can only be used when the source controller is managed by an instance of UINavigationController

I am having a problem with this.
In my root view controller I am having a textfield & one button. I am giving a condition like if i entered 0 in textfield then only it should move to next view.
upto here it is working correctly. But now here is problem. Here I am having one button & given navigation to third view controller for that button. here i am getting error as
Terminating app due to uncaught exception 'NSGenericException', reason: 'Push segues can only be used when the source controller is managed by an instance of UINavigationController.'
image ref: http://img12.imageshack.us/img12/8533/myp5.png
and i am giving action for button in first view as below
- (IBAction)Submit:(id)sender {
if([tf.text isEqual:#"0"])
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
SecondViewController *vc2 = [storyboard instantiateViewControllerWithIdentifier:#"SecondViewControllerID" ];
[self presentViewController:vc2 animated:YES completion:NULL];
}
}
Go To:
Editor--> Embed In --> Navigation Controller, to add Navigation Controller to your initial view
After looking at your screenshot, you either need to
Push your SecondViewController onto the existing navigation controller's stack instead of presenting it modally OR
You need to embed your SecondViewController in another navigation controller and then create and present that navigation controller modally from your SamplesViewController
Either way, SecondViewController needs to be embedded in a navigation controller before you can use Push Segues from it
Either embed your view controller in a Navigation controller or if there is a Navigation controller in the story board mak it the initial view controller
I also faced same problem. My problem was I was using model segue style (rather that push) for one before the current controller because of that I think it broke the Navigation chain before already.
Embed your view controller in a UINavigationController is a good option if there is no UINavigationController in the storyboard. Otherwise you can select the UINavigationController and select the root view controller in the inspector pane, then drag it to the UIViewController you want to use as root. the screenshot is as below:
I solved this by creating a custom UIStoryboardSegue between the UINavigationController and the destination view controller:
-(void) perform
{
assert([self.sourceViewController isKindOfClass:[MyNavigationController class]]);
MyNavigationController *launchController = (MyNavigationController *) self.sourceViewController;
[launchController setViewControllers:#[self.destinationViewController] animated:YES];
}
Try this. It works for me.when you set root view controller to first view and use self.presentViewController ,controller move to next view but instance of navigation controller is only for first view,third view required navigation instance so use self.navigationController instead of presentViewController.
NSString * storyboardName=#"Main";
UIStoryboard *storybord=[UIStoryboard storyboardWithName:storyboardName bundle:nil];
SecondViewController *vc=[storybord instantiateViewControllerWithIdentifier:#"SecondViewControllerID"];
[self.navigationController pushViewController:vc animated:YES];

Resources