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.
Related
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 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];
}];
}
There are 3 view controllers View1,View2 and View3.
From view3 I have to navigate to view1.
I have tried the following code but it doesn't work.
//in View3.m
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex;
{
appDelegate.isComingFromCountries = YES;
[self dismissViewControllerAnimated:YES completion:nil];
}
//in View2.m
-(void)viewWillAppear:(BOOL)animated
{
if (appDelegate.isComingFromCountries == YES)
{
appDelegate.isComingFromCountries = NO;
[self dismissViewControllerAnimated:YES completion:nil];
}
}
But this code doesn't work. How do I handle this?
You can use use presentingViewController for dismissing it,
try this -
[self.presentingViewController.presentingViewController dismissModalViewControllerAnimated:YES];
A -> B -> C
Running the above code in modal C will take you back to A.
You have to use delay method to perform animation so that main thread should start performing in B viewController
[self performSelector:#selector(methodForDissmiss) withObject:nil afterDelay:0.5];
then write dismiss code in selector method to work by your logic.
If you are returning to the root view controller from a series of modally presented view controllers then the following code will work in iOS6
[self.window.rootViewController dismissViewControllerAnimated:NO completion:nil];
I think, It may help you. According to your code( in comments area), You second view controller push from first view controller, then present third from second. So you have to set delegate as second in third. And do your code as below in third VC.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex;
{
appDelegate.isComingFromCountries = YES;
[self dismissViewControllerAnimated:YES completion:^{
[self.delegate dismissModal];
};
}
In SecondVC.m
-(void)dismissModal
{
[self.navigationController popViewControllerAnimated:NO];
}
Also you can pop to view 1 from view 3 on like this:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
[self.navigationController dismissViewControllerAnimated:NO completion:nil];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
You can try this one :
if you are pushing one viewController to another and want to move back then use this one
[self.navigationController popViewControllerAnimated:YES];
if you are presenting viewController use modelly and want to move back then use this one
[picker dismissViewControllerAnimated:YES completion:nil];
also you can try this because first you need to dismiss third viewController then second one.
UIViewController *viewController = [self parentViewController];
[self dismissModalViewControllerAnimated:NO];
[viewController dismissModalViewControllerAnimated:YES];
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];
}];
}
I have a tab bar controller with a view inside a navigation controller. One of the buttons on this pops up a modal view. I set my starting view as the delegate for the modal, and call the following:
- (void)dischargeSaveComplete:(dischargeView *)controller
{
[self dismissViewControllerAnimated:YES completion:nil];
[self.navigationController popViewControllerAnimated:YES];
}
It correctly dismisses the modal view, but it doesn't call the back button. Do I need to do something else since it's inside a tab bar controller?
I tried set both to animation no as seen below, and it doesn't work either.
- (void)dischargeSaveComplete:(ehrxEncounterDischargeView *)controller
{
[self dismissViewControllerAnimated:NO completion:nil];
[self.navigationController popViewControllerAnimated:NO];
}
Found the solution based on one of the answers, because I was in a tab bar controller, I had to call the popviewcontroller from the first view as seen below:
- (void)dischargeSaveComplete:(ehrxEncounterDischargeView *)controller
{
[self dismissViewControllerAnimated:YES completion:^(void)
{
demoView *e = [self.parentViewController.tabBarController.viewControllers objectAtIndex:0];
[e.navigationController popViewControllerAnimated:YES];
}];
}
You want 2 animations to follow one another, which is not allowed as you did it. You either have to cancel one of the animation or place popViewController inside the completion block for your first animation.
[self dismissViewControllerAnimated:YES completion:^(void) {
[self.navigationController popViewControllerAnimated:YES];
}
];
u can try delay in performing second action
[self.navigationController performSelector:#selector(popViewControllerAnimated:) withObject:#"YES" afterDelay:1];
hope it works.. happy coding :)