关闭堆栈中较低的ViewController不会按预期运行 [英] Dismissing a ViewController lower in the stack does not behave as expected
问题描述
我正在构建一个复杂的应用程序,它在中间有一个分支。
在应用程序的某个时刻,会出现一个特定的UIViewController,我们' ll称之为 mainViewController
(缩短 mainVC
)。
mainVC
使用以下代码按代码显示另一个视图控制器(出于隐私原因我删除了部分视图):
UIStoryboard * storyboard = [UIStoryboard storyboardWithName:@SecondaryStoryboardbundle:secondaryBundle];
SecondViewController * secondVC = [storyboard instantiateInitialViewController];
[self presentViewController:secondVC animated:YES completion:nil];
所以 secondVC
稍后会出现另一个视图控制器,名为 thirdVC
。这是使用自定义segue完成的,在上面的代码中使用的故事板中设置,代码如下所示:
@implementation VCCustomPushSegue
- (void)执行{
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
动画:^ {
destinationView.center = CGPointMake(sourceView.center.x,destinationView.center.y);
sourceView.center = CGPointMake(0 - sourceView.center.x,destinationView.center.y);
}
完成:^(BOOL完成){
[self.sourceViewController presentViewController:self.destinationViewController animated:NO completion:nil];
}];
}
@end
当你可以看到这个segue使用自定义动画(从右到左的幻灯片)以模态方式(通过使用 presentViewController:
)呈现目标视图控制器。
所以基本上到这里一切都很好。我使用经典模态动画(从底部向上滑动)呈现 secondVC
,并使用我的自定义转换显示 thirdVC
。
但是当我想要解雇 thirdVC
时,我想要的是直接回到 mainVC
。所以我从 thirdVC
中调用以下内容:
self.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:_animate completion:nil];
这样,我正在调用 dismissViewControllerAnimated:
直接在 mainVC
(由 self.presentingViewController.presentingViewController
引用),我期待 thirdVC
将被动画解雇, secondVC
将在没有动画的情况下消失。
正如Apple在UIViewController类文档中所说:
呈现视图控制器负责解除视图$ b它呈现的$ b控制器。如果您在呈现的视图
控制器本身上调用此方法,它会自动将消息转发给
呈现视图控制器。
如果你连续出现了几个视图控制器,从而构建了一个
的呈现视图控制器堆栈,在视图上调用此方法
控制器在堆栈中较低的位置解除其直接子视图
控制器和堆栈上该子项上方的所有视图控制器。
发生这种情况时,只有最顶层的视图才能以动画
方式解散;只需从
堆栈中删除任何中间视图控制器。最顶层的视图使用其模态转换
样式被解除,这可能与其他视图控制器
在堆栈中使用的样式不同。
问题在于它不会发生什么。在我的场景中, thirdVC
消失,并显示 secondVC
被解除,使用经典模态幻灯片到底部动画。 / p>
我做错了什么?
编辑:
所以@codeFi的答案可能在一个经典项目中有效,但问题在于我正在研究一个框架。所以 mainVC
将在客户端应用程序中, secondVC
和 thirdVC
在我的框架中,在一个单独的故事板中。除了在我的代码中对它的引用之外,我无法以任何其他方式访问 mainVC
,因此很遗憾,unwind segues不是一个选项。
我一直有这个完全相同的问题,我已经成功地通过添加屏幕快照作为子视图来解决它 secondVC.view
,如下所示:
if(self.presentedViewController。 presentsViewController){
[self.presentedViewController.view addSubview:[[UIScreen mainScreen] snapshotViewAfterScreenUpdates:NO]];
}
[self dismissViewControllerAnimated:YES completion:nil];
不漂亮,但似乎有效。
注意:如果您的 secondVC
有一个导航栏,则需要在快照屏幕和添加导航栏之间隐藏导航栏快照作为 secondVC
的子视图,否则快照将显示在导航栏下方,因此在解雇动画期间似乎显示双导航栏。代码:
if(self.presentedViewController.presentedViewController){
UIView * snapshot = [[UIScreen mainScreen] snapshotViewAfterScreenUpdates:没有];
[self.presentedViewController.navigationController setNavigationBarHidden:YES animated:NO];
[self.presentedViewController.view addSubview:snapshot];
}
[self dismissViewControllerAnimated:YES completion:nil];
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.
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];
这篇关于关闭堆栈中较低的ViewController不会按预期运行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!