How to navigate to UIViewController which is not present in navigationStack - ios

I have three UIViewControllers. I am navigating to VC3 from VC1. I want to navigate to VC2 if I click on cancel or done button from VC3.
I have added the VC2 controller to navigation stack programmatically.
DocListViewController *temp1 = [[DocListViewController alloc] initWithNibName:#"DocListViewController" bundle:nil];
[self.navigationController addChildViewController: temp1];
for (UIViewController *controllers in self.navigationController.viewControllers) {
if([controllers isKindOfClass: [DocListViewController class]]) {
DocListViewController *VC2ViewController = (DocListViewController*)controllers;
[self.navigationController popToViewController:VC2ViewController animated:YES];
}
}

What you are doing wrong here is adding it as child view controller,addChildViewController as it as a child of the current view controller does not add it in the navigation stack.
You need to insert the controller in you navigation stack before doing popToViewcontroller.
VC2 *temp1 = [[VC2 alloc] initWithNibName:#"DocListViewController" bundle:nil];
NSMutableArray *vcArray = [NSMutableArray arrayWithArray:self.navigationController.viewControllers] ;
[vcArray insertObject:temp1 atIndex:1]; // ** This index is `1` assuming you only have 2 controllers and we are pushing it in the middle,
// if you have many vc in navigation stack and just want to insert a new vc just before your current vc go with this:
/*
[vcArray insertObject:temp1 atIndex:vcArray.count - 2];
*/
self.navigationController.viewControllers = vcArray;
/* --- ** This part is also not needed:
for (UIViewController *controllers in self.navigationController.viewControllers) {
if([controllers isKindOfClass: [DocListViewController class]]) {
[self.navigationController popToViewController: controllers animated:YES];
}
}
*/
[self.navigationController popViewControllerAnimated:true];
Also: you don't need VC2 *VC2ViewController = (VC2*)controllers;
inside the if block as you only need a UIViewController type object for pop-ing.
I have just edited your code, get the project reference below
Edit:
Adding GitHub link for better reference:
PlayingWithNavigation

You can navigate to VC2 using pushviewContoller
NSString * storyboardName = #"Main";
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle: nil];
VC2 * VC2View = [storyboard instantiateViewControllerWithIdentifier:#"VC2ID"]; // "VC2ID" is the storyboard Id of your view controller
[self.navigationController pushViewController:VC2View animated:YES];

UIViewController *vc2 = [[UIViewController alloc] init];
UIViewController *vc3 = [[UIViewController alloc] init];
[self.navigationController pushViewController:vc2 animated:NO];
[self.navigationController pushViewController:vc3 animated:YES];
Try this.

Related

present a new ViewController but maintain the view stack

I'm trying to update an old IOS (objective-c) app to handle shortcutitems. When the user starts the app from a shortcut I would like to go the viewcontroller they've chosen, but would like them to be able to move back through the view hierarchy, to the original launch screen.
the current code in appdelegate didFinishLaunchingWithOptions looks like this:
UINavigationController *controller = (UINavigationController*)[storyboard instantiateInitialViewController];
self.window.rootViewController = controller;
return YES
And trying this:
UINavigationController *controller = (UINavigationController*)[storyboard instantiateInitialViewController];
self.window.rootViewController = controller;
...
if (fromShortCut) {
InfoViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"info"];
// init vc
vc.info = .....
[controller.navigationController pushViewController:vc animated:NO];
// or [controller pushViewController:vc animated:NO];
}
return YES
Shows the correct View, but there's no Back/Back-arrow or swipe gesture to allow the user to move back to the main screen.
Is this possible?
Many Thanks.
Here you go for your solution
if (fromShortCut) {
InfoViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"info"];
UIViewController *rootController = [UIApplication sharedApplication].keyWindow.rootViewController;
// init vc
vc.info = .....
[rootController.navigationController.navigationBar setHidden:NO];
[rootController.navigationController pushViewController:vc animated:NO];
// or [controller pushViewController:vc animated:NO];
}
else{
UINavigationController *controller = (UINavigationController*)[storyboard instantiateInitialViewController];
self.window.rootViewController = controller;
}
Yes. This is possible.
UINavigationController has a setViewControllers:animated: method that lets you do exactly that.
Pay attention to the documentation here:
viewControllers
The view controllers to place in the stack. The
front-to-back order of the controllers in this array represents the
new bottom-to-top order of the controllers in the navigation stack.
Thus, the last item added to the array becomes the top item of the
navigation stack.
You should create an array of UIViewController objects and the order should like this.. [firstVC, secondVC, ..., topMostVC]
EDIT:
The code should look something like this
UINavigationController *controller = (UINavigationController*)[storyboard instantiateInitialViewController];
self.window.rootViewController = controller;
if (fromShortCut) {
NSMutableArray *viewControllers = [[NSMutableArray alloc] init];
//create other viewonctollerObjeccts
FirstViewController *firstVC = storyboard instantiateViewControllerWithIdentifier:#"first"];
SecondViewController *secondVC = storyboard instantiateViewControllerWithIdentifier:#"second"];
ThirdViewController *thirdVC = storyboard instantiateViewControllerWithIdentifier:#"third"];
InfoViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"info"];
// init vc
vc.info = .....
[viewControllers insertObject:vc atIndex:0];
//finally set the array to nav stack
[controller setViewControllers:viewControllers animated:NO];
}
What this does is, it sets InfoViewController at the top of the navigation stack, and backs out to ThirdViewController which backs out to SecondViewController and so on.

Problems with using popToViewController to go back to a specific view controller going to black screen

I am using doing something basic like this to push to a view.
UIStoryboard *storyboard = self.navigationController.storyboard;
MenuViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"menuViewController"];
[self.navigationController pushViewController:viewController animated:YES];
Some places I can simply use:
[self.navigationController popViewControllerAnimated:YES];
But in a few places I want to pop to a specific view controller. What I have tried is:
UIStoryboard *storyboard = self.navigationController.storyboard;
RecordMenuViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:#"recordMenuViewController"];
[self.navigationController popToViewController:viewController animated:YES];
But it just goes to a black screen like the view isn't in the stack or something. What am I missing here?
If you want to pop to a specific view controller using the navigation stack, do the following:
NSArray* vcs = self.navigationController.viewControllers;
UIViewController* target = [vcs objectAtIndex:([vcs count] - 1) - numVCsToGoBack];
[self.navigationController popToViewController:target];
If you have to pop to specific view controller in the stack use following code:
(here consider you have to pop to MyViewController Class)
for (UIViewController *controller in self.navigationController.viewControllers)
{
if ([controller isKindOfClass:[MyViewController class]])
{
[navigationController popToViewController:controller animated:YES];
break;
}
}

How to switch to next controller on button click in ios (programmaticaly)

I am working on single view application. On click of button i want to switch to next page(let say menu controller). Please specify what changes I have to make in appdelegate to add a navigation controller as I am completely new to iOS.
[button addTarget:select action:#selector(buttonClick) forControlEvents:UIControlEventTouchUpInside]; and implement the selector as
-(void)buttonClick{
UIViewController *menu = [[UIViewController alloc] init];
[self.navigationController pushViewController:menu animated:YES];
}
Add this in the app delegate for the root view controller:
FirstViewController *firstViewController = [[FirstViewController alloc] initWithNibName:#"view name" bundle:nil];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:firstViewController];
self.window.rootViewController = navigationController;
Inside the button click:
SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:#"view name" bundle:nil];
[self.navigationController pushViewController:secondViewController animated:YES];
you have to set UINavigationController as Window.rootViewController like below.
FirstViewController *viewController = [[FirstViewController alloc] initWithNibName:#"FirstViewController" bundle:nil];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
self.window.rootViewController = navigationController;
You should subclass UIViewController and implement the view however you want. Views can be built programmatically or in interface builder.
Then you would either use segues, storyboard identifiers, or a xib file to load the view.
Might look like this: (assuming you set up the view controllers in a storyboard and connected them with appropriate segues & the identifier below)
-(void)buttonClick{
[self performSegueWithIdentifier:#"MySegueIdentifier"];
}
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString: #"MySegueIdentifier"]) {
MyCustomViewController* vc = (MyCustomViewController*)[segue destinationViewController];
//do something with your view controller, like set a property
}
}
Or maybe like this
-(void) buttonClick {
MyCustomViewController* vc = (MyCustomViewController*)[[UIStoryboard storyboardWithName: #"MyStoryboard"] instantiateViewControllerWithIdentifier: #"MyStoryboardIdentifier"];
[self.navigationController pushViewController: vc animated: YES]; //assuming current view controller is a navigation stack. Or could also do presentViewController:animated:
}
You would add a class subclassing UIViewController to your project, and import it (#import "MyCustomViewController.h" in the .m file of the view controller you're pushing from).
Could also use a xib file, but I won't bother with those since Storyboards are much easier to work with.
Without a storyboard:
Inside the app delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
navigationController = [[UINavigationController alloc] init]; //navigation controller is a property on the app delegate
// Override point for customization after application launch.
FirstViewController *firstViewController = [[FirstViewController alloc] init];
[navigationController pushViewController: firstViewController animated:NO];
[window addSubview:navigationController.view];
[window makeKeyAndVisible];
return YES;
}
Inside your FirstViewController:
-(void) buttonClick {
MyCustomViewController* vc = [[MyCustomViewController alloc] init]; // or maybe you have a custom init method
[self.navigationController pushViewController: vc animated: YES];
}
Very simple:
-(void)ButtonClickActionMethod
{
[button addTarget:select action:#selector(buttonClick) forControlEvents:UIControlEventTouchUpInside];
}
Clicked Action:
-(void)buttonClick{
YourViewController *view = [[YourViewController alloc] initWithNibName:#"YourViewController" bundle:nil];
[self.navigationController pushViewController:view animated:YES];
}

How to go to particular viewcontroller from leftviewcontroller in IIViewDeck in storyboard?

I am having difficulty using IIViewDeck in my app. I am using storyboard. I have managed to bring leftviewcontroller which is a tableviewcontroller with cells that are supposed to segue to particular viewcontroller in the storyboard. How do I do this? I have put this in appdelegate.
UIStoryboard* mainStoryboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
UIViewController *menuController = [mainStoryboard instantiateViewControllerWithIdentifier:#"mainSideNavMenu"];
UINavigationController* navigationController = (UINavigationController *) self.window.rootViewController;
self->viewDeckController = [[IIViewDeckController alloc] initWithCenterViewController:navigationController leftViewController:menuController rightViewController:nil];
self.window.rootViewController = self->viewDeckController;
You can manage it with code, with the didSelectRowAtIndexPath method of your table view.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
UIStoryboard* sb = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
if (indexPath.row == 0) {
MyTripsViewController* newController = [sb instantiateViewControllerWithIdentifier:#"ViewController1"];
[self.viewDeckController closeLeftViewBouncing:^(IIViewDeckController *controller) {
self.viewDeckController.centerController = newController;
}];
}
if (indexPath.row == 1) {
MyTripsViewController* newController = [sb instantiateViewControllerWithIdentifier:#"ViewController2"];
[self.viewDeckController closeLeftViewBouncing:^(IIViewDeckController *controller) {
self.viewDeckController.centerController = newController;
}];
}
else {
MyTripsViewController* newController = [sb instantiateViewControllerWithIdentifier:#"ViewController3"];
[self.viewDeckController closeLeftViewBouncing:^(IIViewDeckController *controller) {
self.viewDeckController.centerController = newController;
}];
}
}
So you have to defined you row / viewController couple.
I know it's a bit late, but someone might find the answer useful at some point.
Max's answer is generally a good answer. However, the original poster's question is a bit vague. He/She didn't specify if the transition is required in the center view controller or the left one.
Assuming the transition is in the left view controller:
If you want push transition, you can use a code like:
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0) {
UINavigationController * nc = (UINavigationController *)self.viewDeckController.leftController;
UIViewController * vc = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"yourView"]; // use the name of the view (not the navigation view controller)
[nc pushViewController:vc animated:YES];
}
}
If you want Modal transition, just replace the code within the previous if statement clause with the following code:
UIViewController * vc = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"yourViewName"]; // don't use the name of a navigation controller
UINavigationController * nc = [[UINavigationController alloc] initWithRootViewController:vc];
[self presentViewController:nc animated:YES completion:nil];
The navigation controller in this code is used to get the navigation bar shown. If you don't need the navigation bar, just omit the navigation controller definition and pass the view controller as a parameter instead in the presentViewController: animated: completion: method.
Assuming the transition is in the center view controller:
You can use the code Max had provided. Keep in mind that the way he showed the new view controller is by replacing the existing center view controller. The new view controller is neither pushed nor modally showed. If you want to push new view controller to the existing center view controller, you should use the same way I introduced the transition in the previous two pieces of code above. So, it should look like this:
Push Transition: (the following code should replace the code within the if statement clause in the first piece of code)
[self.viewDeckController closeLeftView];
UINavigationController * nc = (UINavigationController *)self.viewDeckController.centerController;
[nc pushViewController:[[[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"yourViewName"] parentViewController] animated:YES];
Modal Presentation: (the following code should replace the code within the if statement clause in the first piece of code)
[self.viewDeckController closeLeftView];
UINavigationController * center = (UINavigationController *)self.viewDeckController.centerController;
UIViewController * vc = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"yourViewName"];
UINavigationController * nc = [[UINavigationController alloc] initWithRootViewController:vc];
[center presentViewController:nc animated:YES completion:nil];

pop to TableViewController from Detail Controller

I have a ViewController1 which can do a push segue into a ViewController2. This, in turn, can do a push segue into a ViewController3. I have a UIBarButtonItem in the ViewController1 that can do a push segue into the ViewController3. However, when I press the back button in the ViewController3, I need it to pop to ViewController2.
How would I do this? Here's the code I tried:
ViewController2 *VC2 = [[ViewController2 alloc] init];
ViewController3 *VC3 = [[ViewController3 alloc] init];
[self.navigationController pushViewController:VC2 animated:NO];
[self.navigationController pushViewController:VC3 animated:YES];
Tried your solution, and seems to be working for me,
but, anyway.. if for any reason it doesn't work for you... try with this:
NSArray *array = self.navigationController.viewControllers;
[self.navigationController setViewControllers:[array arrayByAddingObjectsFromArray:#[vc1,vc2]] animated:YES];
Here's what I finally found, based on the answer from #Camo. I present ViewController3 from ViewController1 via. Segue. Then, in the ViewController3 viewDidLoad, I put this code:
NSArray *array = self.navigationController.viewControllers;
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
id TVC = [storyboard instantiateViewControllerWithIdentifier:#"VC2"];
[self.navigationController setViewControllers:[array arrayByAddingObjectsFromArray:#[TVC, self]] animated:NO];

Resources