I have the following situation:
view controller A -> presents modally -> view controller B
view controller B -> presents modally -> view controller C
I would like to dismiss view controller "C" and go directly to "A" instead of showing "B" since it do not make sense to show "B" at that time.
How can I accomplish that ?
Thanks,
Daniel
In 'view controller C' ->
Before iOS 6:
Use
[self.parentViewController.parentViewController dismissModalViewControllerAnimated:YES];
Or,
[self.presentingViewController.presentingViewController dismissModalViewControllerAnimated:YES];
From and Above iOS 6:
Use
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:nil];
You can use segues to present view controllers from other view controllers.
To go backwards through a hierarchies you normally dismiss presented view controllers or you go back to specific view controllers through unwind segues.
Try the following:
[vcB dismissModalViewControllerAnimated:NO] //no Animation, so happens instantly
[vcA dismissModalViewControllerAnimated:YES] //with Animation, this is all you see
Your best bet would be use navigation controllers if your B and C are related and are more detailed version of A
A->B-C . You unwindsegue to unwind the stack/pop the view controllers pushed on the stack.
Read this link very useful - http://chrisrisner.com/Unwinding-with-iOS-and-Storyboards
This is an old question and has an accepted answer but it did not solve my problem. Therefore, I would like to propose another solution for those who need different approaches.
The story is A presents B, B presents C, A is shown when C is dismissed.
Here is my approach;
Present ViewB from ViewA, when it comes to presenting ViewC from ViewB, do it from ViewA, and dismiss ViewB as follows;
let presentingNavCon = navigationController?.presentingViewController as? UINavigationController
let viewC = ViewC()
navigationController?.dismiss(animated: false)
presentingNavCon?.present(viewC, animated: true)
so, when you dismiss ViewC, ViewA appears.
Related
I'm presenting UIViewController B modally from UIViewController A. Then, there is a UINavigationController between B and C, and C is flipped from B. I want to dismiss both B and C and animate straight to A, without showing B and hence without calling B's viewDidLoad function. I'm calling dismissViewControllerAnimated from A, but that still shows B first and hence calls B's viewDidLoad function. Forgive me if there is already a SO answer on this; I've been snooping around for hours and just can't find an answer. How can I solve this?
Any Parent ViewController that is presented modally can be dismissed using:
[self.parentViewController dismissModalViewControllerAnimated:YES];
Another way to do it would be using:
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:nil];
Let me know if it doesn't works.
I have viewcontroller A and on click of button, i have opened a another viewcontroller with presentation style as Form sheet. In second view controller which is opened have two buttons. Now, when these buttons are clicked, this second view controller should go away and next view controller should open on top of view controller A. But when i am trying below, another view controllers are opening up inside the dialog
i don't know how to unwind this segue and call another scene together.
Nitya, did you try the following piece of code to dismiss current view controller. Use it in the IBAction of the button where you want to dismiss the viewController:-
self.dismissViewControllerAnimated(true, completion: nil)
So you have a root viewcontroller A with a button. If you tap that button, an other viewcontroller (let's name it B) is presented by A as a form sheet. B has two buttons and if you tap one of those buttons, B should be dismissed and after a different viewcontroller (let's say C) shold be presented by A.
Apple don't really recommend this kind of workflow, nevertheless it is possible to implement it. You may shold consider to use navigation controller or master-detail controller instead of this. But if you stick to your original idea here are some possible implementations:
1.
If you are using a storyboard and the button on B triggers an unwind segue to A then you can add this to the end of the unwind seque action:
dispatch_async(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:#"segueThatPresentsC" sender:nil];
});
2.
If you present your viewcontrollers programmatically then:
Before you present B from A you can configure a button of B so that ist target is A and and its action is a method defined in A:
- (void) dismissAndPresentC {
[self dismissViewControllerAnimated:YES completion:^{
[self presentViewController:instanceOfC animated:YES completion:nil];
}];
}
This second is maybe a bit smaller hack, but still a confusing concept.
My Application flow is as below where A, B , c and D are view controllers.
Arrows mark presenting from and to view controllers.
Now I need home button in B , C and D view controller that navigate back to A.
I am not using storyboard.
Its I am unable to use dismissviewcontroller as it dismisses just once, where in some cases its required 2 or 3 previous view controllers dismiss.
Any suggestions in this regards will be helpful.
It sounds like you should be using A as your root view controller on a UINavigationController. The only thing B, C, and D will need to do is call popToRootViewController.
You'll need to make your login view controller be pushed from A, but you can do it without the user seeing it by putting the code in the AppDelegate (which is likely where you're checking to see if the user needs to log in anyway).
How about using setViewControllers:animated:. Where ever you are, you get the first View controller as firstViewController = [self.navigationController viewController] firstObject], then [self.navigationController setViewControllers:#[firstViewController] animated:YES].
See here: setViewControllers:animated:
There are a lot of stuff on the net according the topic but I don't get it. I have an App with Custom segue implementation and without Navigation controller. There are cases in which I need to unwind back several steps.
For implementation I use simple calls:
CODE CUSTOM SEGUE
For wind:
[[self sourceViewController] presentModalViewController:[self destinationViewController] animated:YES];
For unwind:
[[self destinationViewController] dismissViewControllerAnimated: YES completion: nil];
As I understand when I wind segue somewhere in the memory there is data which is used during the unwind. For that reason in the custom unwind I only use read only property destinationViewController.
So how can I unwind several steps back in one action? Or I have to make several unwinds in different View controllers?
I read the following question, but I don't understand implementation.
Bellow I put example of my apps logic:
EXAMPLE
I have 4 VC which is in a chain:
VC A -> VC B -> VC C -> VC D
I wind and unwind back and forth. The logic is ok. There are situation in which I need to unwind back from VC D to VC B. How to do that? Can I unwind directly to VC B or I have to unwind to VC C and then in the unwind handler to unwind to VC B?
I also thought of additional segue from VC D to VC B, but there are remarks on the net that this is not the right way, because segue chain will get messy.
The answer to What are Unwind segues for and how do you use them? has everything you need to know about unwindSegues (I suggest you re-read it).
But for a more direct answer, yes you can unwind back from VC D to VC B. To do that you have to first implement the method in VC B:
- (IBAction)unwindToVCB:(UIStoryboardSegue *)unwindSegue
{
}
after doing so, go to the IB, and control-drag a button's action to the Exit icon, you should then pick the method you created above as the selector. (This is taken directly from the question/answer stated above).
Again, for a clearer version of what I said, read the answer of the linked question I mentioned above.
You have to use UINavigationController, just add it in storyboard as mainViewController and set 'A' ViewController as root view controller for it, then change all segues to push segue, set 'Identifires' for them, and you can use performSegueWithIdentifire to push view controller and inside view controller:
[self.navigationController popViewControllerAnimated:];
or
[self.navigationController popToViewController: animated:];
to dismiss it.
Here is my storyboard configuration:
Navigation Controller -> View Controller A -> Push-> View Controller B
^
|
Modal
^
|
View Controller C
What I want to achieve: When a button is pressed in View C, directly View B will be opened modally (No part of View A is to be displayed). Also, View B will have a navigation back button to View A.
To achieve this,
I set up the illustrated storyboard.
I created a segue between View C and the Navigation Controller of View A/B.
In the 'prepareForSegue' method of View Controller C, I get an instance of View Controller A as the first element in the navigation. In this instance, I set a variable like 'directlyProceedToViewB=YES'.
In the viewDidLoad method of View Controller A, I check the variable 'directlyProceedToViewB' and if it is YES, I call 'performSegueWithIdentifier' to segue to View B
The result is so that, first View A is opened modally and after displaying it a very short time, View B is opened with a push animation (View B can navigate back to View A, which is good). But I do not want View A to be displayed any time at all. How can I achieve this?
EDIT:
To better visualize, I'm adding a screenshot with more example cases to support:
Here are some cases I want to support:
We can start with ViewC, click on 'Modally Display B' which opens ViewB, then click 'Back to A' to navigate back to ViewA, then click on 'Dismiss Modal' on ViewA to go back to ViewC
We can start with ViewD, clcik on 'Modally Display A' which opens ViewA, then click on 'PushB' to open ViewB, then go back and forth between A and B and modally dismiss to ViewD.
First of all, some corrections: those are not views but view controllers. And "view A" is not pushed into the UINavigationController but it's the root.
After that, I suggest making the segue in "view C" an unwind segue and implement the IBAction in "view A" by pushing "view B" with [[self navigationController] pushViewController:bViewController animated:NO].
EDIT (adding some details):
I assume that in ViewControllerA's viewWillAppear you present ViewControllerC in a not animated manner.
Implement an unwinding action like (IBAction)unwindAndThenGoToB:(UIStoryboardSegue *)segue in ViewControllerA.
In the storyboard connect the button in ViewControllerC to the Exit icon and select the previously defined method.
Then implement the method with the push call I wrote earlier.
ps: for documentation there is plenty on Apple's website.
Implement this using delegates.Decalre protocol in which class you want and define those methods and call the methods in the view controller you want.There is no many ways of calling some view and showing back button to go different view.modal view is just a concept.and you can use delegate methods to call whatever class you want.
Here I got a way to do so:-
You need to set no animation for segue from viewC to viewA as shown in below image. Then set a segue identifier for segue from viewA to viewB namely, "viewB" and in your viewA .m file add following code,
- (void)viewDidLoad {
[super viewDidLoad];
// Place your conditional check here.
[self performSegueWithIdentifier:#"viewB" sender:self]; //Will directly lead to viewB and viewA won't be shown as no animation is there from viewC to viewA.
}
And your rest flow be like-wise.
I found the solution myself.
First, I discovered that, my original proposal of
In the viewDidLoad method of View Controller A, I check the variable
'directlyProceedToViewB' and if it is YES, I call
'performSegueWithIdentifier' to segue to View B
works as I desired on iOS 7 but does not work on iOS 8.
So the solution is, in the viewDidLoad method of View Controller A, if 'directlyProceedToViewB' is YES, rather than calling performSegueWithIdentifier, use the following code:
ViewControllerB *destVC = [self.storyboard instantiateViewControllerWithIdentifier:#"ViewControllerBStoryboardID"];
[self.navigationController pushViewController:destVC animated:NO];