问题
I'm building a complex app that has kind of a branch in the middle.
At some point in the app, a particular UIViewController is presented, we'll call it mainViewController
(shortened mainVC
).
The mainVC
presents another view controller, by code, using the following code (I strip out parts of it for privacy reasons):
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"SecondaryStoryboard" bundle:secondaryBundle];
SecondViewController *secondVC = [storyboard instantiateInitialViewController];
[self presentViewController:secondVC animated:YES completion:nil];
So the secondVC
will later present another view controller, called thirdVC
. This is done using a custom segue, set in the storyboard used in the code above, which code looks like this:
@implementation VCCustomPushSegue
- (void)perform {
UIView *sourceView = ((UIViewController *)self.sourceViewController).view;
UIView *destinationView = ((UIViewController *)self.destinationViewController).view;
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
destinationView.center = CGPointMake(sourceView.center.x + sourceView.frame.size.width, destinationView.center.y);
[window insertSubview:destinationView aboveSubview:sourceView];
[UIView animateWithDuration:0.4
animations:^{
destinationView.center = CGPointMake(sourceView.center.x, destinationView.center.y);
sourceView.center = CGPointMake(0 - sourceView.center.x, destinationView.center.y);
}
completion:^(BOOL finished){
[self.sourceViewController presentViewController:self.destinationViewController animated:NO completion:nil];
}];
}
@end
As you can see this segue presents the destination view controller modally (by the use of presentViewController:
) with a custom animation (a slide from right to left).
So basically up to here everything is fine. I present the secondVC
with a classic modal animation (slide up from bottom) and present the thirdVC
with my custom transition.
But when I want to dismiss the thirdVC
, what I want is to go back directly to the mainVC
. So I call the following from the thirdVC
:
self.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:_animate completion:nil];
That way, I'm calling dismissViewControllerAnimated:
directly on mainVC
(referenced by self.presentingViewController.presentingViewController
), and I'm expecting the thirdVC
to be dismissed with an animation, and the secondVC
to just disappear without animation.
As Apple says in the UIViewController Class Documentation:
The presenting view controller is responsible for dismissing the view controller it presented. If you call this method on the presented view controller itself, it automatically forwards the message to the presenting view controller.
If you present several view controllers in succession, thus building a stack of presented view controllers, calling this method on a view controller lower in the stack dismisses its immediate child view controller and all view controllers above that child on the stack. When this happens, only the top-most view is dismissed in an animated fashion; any intermediate view controllers are simply removed from the stack. The top-most view is dismissed using its modal transition style, which may differ from the styles used by other view controllers lower in the stack.
The issue is that it's not what happens. In my scenario, the thirdVC
disappears, and shows the secondVC
being dismissed with the classic modal slide to bottom animation.
What am I doing wrong ?
Edit :
So @codeFi's answer is probably working in a classic project, but the problem here is that I'm working on a framework. So mainVC
would be in a client app, and the secondVC
and thirdVC
are in my framework, in a separate storyboard. I don't have access to mainVC
in any other way than a reference to it in my code, so unwind segues are unfortunately not an option here.
回答1:
I've been having this exact same issue, and I've managed to visually work around it by adding a snapshot of the screen as a subview to secondVC.view
, like so:
if (self.presentedViewController.presentedViewController) {
[self.presentedViewController.view addSubview:[[UIScreen mainScreen] snapshotViewAfterScreenUpdates:NO]];
}
[self dismissViewControllerAnimated:YES completion:nil];
Not pretty, but it seems to be working.
NOTE: if your secondVC
has a navigation bar, you will need to hide the navigation bar in between snapshotting the screen and adding the snapshot as a subview to secondVC
, as otherwise the snapshot will appear below the navigation bar, thus seemingly displaying a double navigation bar during the dismissal animation. Code:
if (self.presentedViewController.presentedViewController) {
UIView *snapshot = [[UIScreen mainScreen] snapshotViewAfterScreenUpdates:NO];
[self.presentedViewController.navigationController setNavigationBarHidden:YES animated:NO];
[self.presentedViewController.view addSubview:snapshot];
}
[self dismissViewControllerAnimated:YES completion:nil];
回答2:
I had the same issue and I've fixed it by using UnwindSegues.
Basically, all you have to do is add an IBAction Unwind Segue method in the ViewController that you want to segue to and then connect in IB the Exit action to your Unwind Segue method.
Example:
Let's say you have three ViewControllers (VC1, VC2, VC3) and you want to go from VC3 to VC1.
Step 1 Add a method to VC1 like the following:
- (IBAction)unwindToVC1:(UIStoryboardSegue*)sender
{
}
Step 2 Go in Interface Builder to VC3 and select it. Then CTRL-drag from your VC icon to Exit icon and select the method you've just added in VC1.
Step 3 While still in IB and with VC3 selected, select your Unwind Segue and in the Attributes Inspector add a Segue Identifier.
Step 4 Go to VC3 where you need to perform your segue (or dismiss the VC) and add the following:
[self performSegueWithIdentifier:@"VC1Segue" sender:self];
来源:https://stackoverflow.com/questions/26017607/dismissing-a-viewcontroller-lower-in-the-stack-does-not-behave-as-expected