I have this navigation stack
RootVC ---> VC1 --> (presenting)-> ModalVC
and I have VC2 (not in navigation stack).
When presenting ModalVC, I want to click on button in my ModalVC to dismiss ModalVC, then push VC2 into the navigation stack after VC1 at one click. It should look like this:
RootVC ---> VC1 ---> VC2
I tried a lot of methods to make it, but pushing event fire only, when I return to my RootVC.
I tried to make it with delegates:
In ModalVC on click:
[self dismissViewControllerAnimated:YES completion:^{
if ([self.delegate respondsToSelector:#selector(dismissAndPush:)]) {
[self.delegate performSelector:#selector(dismissAndPush:) withObject:VC2];
}
}];
In VC1:
- (void)dismissAndPush:(UIViewController *)vc {
[self.navigationController pushViewController:vc animated:NO];
}
Please help to understand this behavior. Where is my mistake?
From Apple Documentation:
The presenting view controller is responsible for dismissing the view
controller it presented.
So, VC1 should be dismissing the ModalVC, try to do this
ModalVC on click:
if ([self.delegate respondsToSelector:#selector(dismissAndPush:)]) {
[self.delegate performSelector:#selector(dismissAndPush:) withObject:VC2];
}
In VC1:
- (void)dismissAndPush:(UIViewController *)vc {
[self dismissViewControllerAnimated:YES completion:^{
[self.navigationController pushViewController:vc animated:NO];
}];
}
Error has been in other. If Im right understand: some animations before dismissing presented view controller are blocking animations in navigation stack. I solved this problem with 2 ways:
1) deleteting or set right animations before dismissing
2) use setViewControllers in navigation controller (I select it)
- (void)dismissAndPush:(UIViewController *)vc {
[self dismissViewControllerAnimated:NO completion:^{
NSMutableArray *mutableControllers = [NSMutableArray arrayWithArray:self.navigationController.viewControllers];
NSArray *controllers = [mutableControllers arrayByAddingObject:vc];
[self.navigationController setViewControllers:controllers animated:NO];
}];
}
Related
My storyboard is using a UINavigationController(VC0), I segue using a UIPopover to load a new UIViewController (VC1). From this new UIViewController, I am popping to a new UIViewController (VC2). When I attempt to close this newest popover, I am being quit back to the UINavigationController.
The code that I'm using in VC0 to show the VC1 as popover, VC1 to VC2 is the same code (different identifier though):
[self performSegueWithIdentifier:#"titlePopover" sender:self];
The code that I'm using in VC2 to dismiss the popover is:
UIViewController *vc = [self presentingViewController];
[self dismissViewControllerAnimated:YES completion:^{
[[vc presentingViewController] dismissViewControllerAnimated:YES completion:nil];
}];
What it does is dismisses VC2, shows VC1 for a split second, then dismisses VC1 and goes back to the VC0. I want to be able to dismiss VC2 only, so that I'm on VC1
If you performing sugue modally, use code navigate back:
[self dismissViewControllerAnimated:YES completion:nil];
If performing push segue, use code to navigate back:
[self.navigationController popViewControllerAnimated:YES];
I have a UIViewControllerC which is call from two another UIViewcontroller
ViewControllerA
ViewControllerB
From ViewControllerA to go to UIViewControllerC i have to make it presentviewcontroller
UIViewControllerC *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"UIViewControllerC"];
[vc setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
vc.tagfrom=#"present";
[self presentViewController:vc animated:NO completion:nil];
From ViewControllerB to go to UIViewControllerC i have to make it push view
UIViewControllerC *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"UIViewControllerC"];
[vc setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
vc.tagfrom=#"push";
[self.navigationController pushViewController:vc animated:YES];
Now i have to back from both view on back button i check tagfrom condition and handle it
-(IBAction)backBtn:(id)sender
{
if ([tagfrom isEqualToString:#"present"])
{
[self dismissViewControllerAnimated:NO completion:nil];
}
else
{
[self.navigationController popViewControllerAnimated:YES];
}
}
Which working fine in both senerio, but sometimes my push view behaves like presentmodelveiw, and having no transition effects in it, please help me to resolve it
First of all, you don't need tagfrom property on your UIViewController subclass.
A UIViewController instance has a property called presentingViewController which will let you know about the viewController ( A in your case ) that presented current viewController ( C in your case ).
-(IBAction)backBtn:(id)sender
{
if (nil != self.presentingViewController) {
[self dismissViewControllerAnimated:NO completion:nil];
}
else {
[self.navigationController popViewControllerAnimated:YES];
}
}
Second, modalTransitionStyle is supposed to work with only presentation and NOT push / pop transitions. If you are using this with push / pop, the behavior is undefined because it is not meant to be used there.
I have a photo selection flow that that goes as such:
VC1 push to VC2, present modal, dismiss modal, push VC3.
Upon dismissing the modal view however, self.navigationController is null
Modal View:
[self dismissViewControllerAnimated:YES completion:^{
FBGalleryVC *vc = [[FBGalleryVC alloc] init];
[vc showVC3];
}];
Triggers VC2:
- (void)showVC3 {
NSLog(#"NavController=%#",self.navigationController);
VC3 *vc3 = [self.storyboard instantiateViewControllerWithIdentifier:#"VC3"];
[self.navigationController pushViewController:vc3 animated:YES];
}
It's unclear to me why the navigationController is getting 'unset' or returning as null.
I have a navigation controller A on which i push the view controller B. From B i present modally the view controller C. I need to dismiss C and pop B at the same time. I would like to that in sequence, keeping the dismiss animation first and then the pop animation from B to A. I tried without success this code:
[self dismissViewControllerAnimated:YES completion:^{
[self.presentingViewController.navigationController popViewControllerAnimated:YES];
}];
Any suggestion on how can i achieve this?
If you are writing in C viewcontoller then :
UIViewController *pvc = self.presentingViewController;
UINavigationController *navController = [pvc isKindOfClass:[UINavigationController class]] ? (UINavigationController *)pvc : pvc.navigationController;
[self dismissViewControllerAnimated:YES completion:^{
[navController popViewControllerAnimated:YES];
}];
or if in B view controller
[self.presentedViewController dismissViewControllerAnimated:YES completion:^{
[self.navigationController popViewControllerAnimated:YES];
}];
I had tried popping two times in succession before but not dismissing one and popping another one. You can try what I did and see if it works for you.
In Subview B:
- (void)subViewCController:(SubViewCController *)controller didSelectID:(NSNumber *)theID
{
// do something with theID...
// for my case, I popped
// [self.navigationController popViewControllerAnimated:YES];
// for your case
[self dismissViewControllerAnimated:YES completion:nil];
// Somehow, adding a small delay works for me and the animation is just nice
[self performSelector:#selector(backToSubViewA) withObject:nil afterDelay:0.6];
}
- (void)backToSubViewA
{
[self.navigationController popViewControllerAnimated:YES];
}
Are you using storyboards and segues? If so, you can use unwind segue:
In your first view controller (the one you want to jump back to, not the one you're returning from), create an unwind segue action:
- (IBAction)gotoMainMenu:(UIStoryboardSegue *)segue
{
// if you need to do anything when you return to the main menu, do it here
}
Then in storyboard, you can create a segue from the "dismiss" button to the exit outlet icon () in the bar above the scene, and you'll see main menu listed there.
Sorry but none of the similar questions provide a working solution.
New single-view project.
Storyboard actions:
VC1 is embedded in nav-controller
a button in VC1 activates a push seque into VC2
a button in VC2 activates a modal segue into VC3
VC3 has a button, and a UIViewController-subclass to handle the button action
Problem statement: How can I have the button of the modal VC3 close both VC3 and VC2 at once, taking me back to VC1?
This did not work - takes me to VC2 only:
- (IBAction)dismissPressed:(id)sender {
UINavigationController *myNavController = [self navigationController];
[self dismissViewControllerAnimated:NO completion:^{
[myNavController popToViewController:[myNavController.viewControllers objectAtIndex:1] animated:NO];
}];
}
Thank you very much!
Ok guys, here is the solution:
If you can limit yourself to ios6+, the right answer is to make the button an unwind segue as described in What are Unwind segues for and how do you use them?
But if you are like me and must comply to ios5, the solution goes likes this:
In the VC who calls the modal segue declare a delegate like this:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"segueModalVC"]) {
ModalVC *vc = [segue destinationViewController];
vc.prevVC = self;
}
}
You will have to #import the header for the destination modal VC.
Now in the modal VC itself add a property to hold the previous VC like this:
#property (weak, nonatomic) UIViewController *prevVC;
And now the button's action for popping both VCs should look like this:
- (IBAction)pressedMainMenu:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
[[self.prevVC navigationController] popViewControllerAnimated:NO];
}
[EDITED to show the final version which works perfectly and can do flip animation from VC3 back to VC1. Took me hours to finalize this but now you can enjoy it for free :) ]
IMHO the fact that the modal VC has no 'native' method to access its preceding VC is a design bug.
Use self.presentingViewController to find out the "previous view controller".
You do not need to pass the previous view controller through the property.
- (IBAction)dismissPressed:(id)sender {
UIViewController *presentingViewController = self.presentingViewController;
[self dismissViewControllerAnimated:NO completion:^{
[self.presentingViewController popViewControllerAnimated:TES];
}];
}
Try to Use popToRootViewControllerAnimated method to go back VC1.
- (IBAction)dismissPressed:(id)sender {
UINavigationController *myNavController = [self navigationController];
[self dismissViewControllerAnimated:NO completion:^{
[myNavController popToRootViewControllerAnimated: NO];
}];
}