Assume that we have 3 view controllers: A, B, and C. A is the root view controller, which has presented B, and B has in turn presented C. How can we perform a custom unwind segue from C to A that does not reveal B?
A - B - C
A UIStoryboardSegue has a reference to its source view controller as well as its destination view controller, but what about the view controllers in between (B in our example)? We can perform whatever animations we want on C, but I don't see how we can affect B in any way.
The goal is simply to dismiss all but the root (B and C) to the right while having A come in from the left, so both source and destination are swiping horizontally next to each other. B should not be visible at any point of the animation.
My example dismisses only two views, but I hope to find a solution that would apply to an arbitrary number of views. Furthermore, I am not interested in solving this using a UINavigationController. I have tried simply dismissing B, which does indeed dismiss C as well, but you can still see both B and C during the animation.
You can dissmiss your controller as below :
self.presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil) // you need to track viewcontroller's stack hierarchy
Related
If a view controller A is modally presented and it contains a container view containing a view controller B.
Then if B wishes to dismiss itself (which in effect is also effectively dismissing A because B is contained within A) then should B call self.dismiss() or self.parent?.dismiss()?
Since B is a separate entity and B may not necessarily be contained in A, if B wishes to dismiss itself, it can call self.dismiss().
There will be 2 cases. If B is presented by itself, then it would dismiss as usual. If B is contained, then the OS would see that it's contained within A, then dismiss A.
However, if the only use of B is to be contained in A, then it makes sense to let A handle the navigation. The part where B "wishes" for itself to be dismissed can be done using delegates or blocks.
I have a Navigation Controller (NC) and three ViewControllers (A, B, C) with the following navigation pattern:
NC->A->B->C
If I go from A to C and 'back' both B and C deinit method gets called.
If I use an Unwind Segue to go from C to A, B deinit does not get called.
Not clear why - I have another similar sequence in my App and deinits get called regardless of 'back' or 'unwind' operation.
Any idea what could cause B to 'stay alive' post an unwind operation?
Found the issue. The problem is this line I had in viewDidLoad:
definesPresentationContext = true
From the docs:
Determines which parent view controller's view should be presented over for presentations of type UIModalPresentationCurrentContext. If no ancestor view controller has this flag set, then the presenter will be the root view controller.
As a result, the middle view (i.e. 'B') becomes the root unless it is dismissed by a 'back' operation.
To avoid having the search box still visible for a split second on view C, I added searchController.active = false in prepareForSegue of view B after I obtain the chosen value from user selection (tap on row).
I am an experienced iOS developer, but I've stumbled upon an issue that I'm not entirely sure how to solve.
Lets say for example I have 3 UIViewControllers, A, B, and C respectively. A is the root and B is presented on top of A and C is presented on top of B.
B and C are presented using presentViewController:animated:completion:
So the presentation stack looks like this.
[A] -> [B] -> [C]
In my program, I want to dismiss B and only B. The docs for
dismissViewControllerAnimated:completion: says that if I dismiss B, it will ask its A to dismiss B and then will also dismiss C as well. I do not want that. I want to dismiss B only such that A will choose C as its presentedViewController like so
[A] -> [C]
Is this possible?
--------Notes-------
I realize that this seems more suited for another presentation pattern where A,B,C would be siblings under a common parentViewController. But I May not use that.
The presentedViewController/presentingViewController pattern is just like a doublylinked list. However, since these properties are read-only, I can not do any node manipulation.
Could you use a navigation controller with the navigation bar hidden and push the controllers rather than present them (using a push and pop animation that mimics that of presentation).
Then use setViewControllers to replace the ABC stack with an AC stack?
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:
I have three view controllers A, B and C.
C is the target.
From A, I have a segue named showCFromA to view controller C.
From B, I have another segue named showCFromB to view controller C.
Now, when C is displayed (shown from B), I tap on the "Back" button, but at this stage, it shows A, and not B as I expected.
How can I fix that?
Don't mess with Back - it makes for a disjointed app experience. You end up at a place you don't expect to be and navigation just doesn't feel right.
If you have a B on the stack, you can just
popToViewController:animated:
to return to the specific view controller (B) that you want to see.
If you have gone from A directly to C with no intervening stop at B, you can't go there with back. Instead you should just push a B.
If your B should be on the stack - i.e. you went from B to C - then B is where you should end up if you simply go back. If that is currently not the case you need to post some more details to help diagnose the problem.
What is confusing right now is what you actually have on the stack. You mention being at A and going to C, then being at B and going to C, but the order in which you do this (and if these are two separate cases) affects the outcome.
After checking the source again, I found the issue is not properly handling navigation vc stack. When push new VC from B, when viewWillDisapper is called (B), I added "popViewController". Therefore, navigation view controller array has count of 2 (the middle element is removed). This makes strange behavior: From view controller C, I cannot go back.