关闭堆栈中较低的ViewController的行为与预期不符。

10

我正在开发一个比较复杂的应用程序,在中间有一个分支。

在应用程序的某个时刻,会呈现一个特定的UIViewController,我们称之为mainViewController(简称mainVC)。

mainVC通过以下代码呈现另一个视图控制器(由于隐私原因,我删除了部分代码):

UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"SecondaryStoryboard" bundle:secondaryBundle];
SecondViewController *secondVC = [storyboard instantiateInitialViewController];
[self presentViewController:secondVC animated:YES completion:nil];

因此secondVC稍后将呈现另一个名为thirdVC的视图控制器。这是使用在上面的代码中使用的故事板中设置的自定义segue完成的,其代码如下:

@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

正如您所看到的,这个segue通过使用presentViewController:以自定义动画(从右向左滑动)模态呈现目标视图控制器。

因此,基本上到这里一切都很好。我使用经典的模态动画(从底部向上滑动)呈现secondVC,并使用自定义过渡呈现thirdVC

但是当我想要关闭thirdVC时,我希望直接返回到mainVC。 因此,我从thirdVC中调用以下内容:

self.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:_animate completion:nil];
那么,我直接在self.presentingViewController.presentingViewController中引用的mainVC上调用dismissViewControllerAnimated:来期望使用动画解散thirdVC,并使secondVC仅消失而不使用动画。如苹果在UIViewController类文档中所述,呈现视图控制器负责解雇它呈现的视图控制器。如果您在呈现的视图控制器本身上调用此方法,则会自动将消息转发到呈现的视图控制器。如果您依次呈现多个视图控制器,则构建一个呈现的视图控制器堆栈,调用此方法会解散堆栈中较低的视图控制器及其上面的所有视图控制器的直接子视图控制器。当这种情况发生时,仅以动画方式解除最顶部的视图;任何中间视图控制器都将从堆栈中删除。使用其模态转换样式解雇最顶部的视图,该样式可能与堆栈中较低的其他视图控制器使用的样式不同。问题在于这不是发生的事情。在我的场景中,第三个VC消失了,并且显示出第二个VC正在通过经典的模态向下滑动动画解散。我做错了什么?编辑:因此,@codeFi的答案可能适用于经典项目,但问题在于我正在使用框架。因此,mainVC将在客户端应用程序中,并且secondVC和thirdVC位于我的框架中,在单独的storyboard中。我无法以任何方式访问mainVC,而仅以代码中的引用方式,因此无法使用展开退步。

1
这种行为变化发生在iOS 8中,在7中它是正确的。我现在正在尝试解决它。 - theLastNightTrain
@theLastNightTrain:嗯,你说得对,这只发生在iOS 8上。如果你在你那边找到了什么,请告诉我。 - rdurand
@theLastNightTrain:有更新吗?如果有人能解决这个问题并提供答案,我很乐意提供悬赏。 - rdurand
抱歉,我的情况下我尽可能地绕过了它。我注意到关闭动画有所帮助,但并不完美,这意味着您无法获得标准动画。 - theLastNightTrain
2个回答

3

我一直遇到这个完全相同的问题,但是我通过将屏幕截图作为secondVC.view的子视图来进行了视觉处理,就像这样:

if (self.presentedViewController.presentedViewController) {
    [self.presentedViewController.view addSubview:[[UIScreen mainScreen] snapshotViewAfterScreenUpdates:NO]];
}

[self dismissViewControllerAnimated:YES completion:nil];

不太美观,但似乎可以正常工作。

注意:如果您的secondVC有一个导航栏,您需要在截取屏幕快照并将快照添加为secondVC的子视图之间隐藏导航栏,否则快照将出现在导航栏下方,似乎在解除动画期间显示了双重导航栏。 代码:

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];

1
看起来运行得相当不错。在他们修复它之前,它会一直很好。谢谢! - rdurand
请注意,如果您的 secondVC 有一个导航栏,您需要在快照屏幕并将快照作为 secondVC 的子视图添加之间隐藏导航栏,否则快照将出现在导航栏下方,在解除动画期间似乎显示了双重导航栏。 - andersblehr
谢谢你的建议,将其直接添加到你的答案中可能会很有用。对我来说,状态栏在两个ViewControllers上都是隐藏的,所以没有问题 :) - rdurand

2
我遇到了同样的问题,通过使用UnwindSegues解决了它。
基本上,你只需要在你想要segue到的ViewController中添加一个IBAction Unwind Segue方法,然后在IB中连接Exit操作到你的Unwind Segue方法即可。
例如:
假设你有三个ViewControllers(VC1、VC2、VC3),你想从VC3跳转到VC1。 步骤一 在VC1中添加以下方法:
- (IBAction)unwindToVC1:(UIStoryboardSegue*)sender
{
}

步骤 2 在 Interface Builder 中选择 VC3,然后从您的 VC 图标 CTRL 拖到 Exit 图标并选择您刚添加在 VC1 中的方法。

添加 Unwind Segue

步骤 3 仍然在 IB 中,并选择 VC3,请选择您的 Unwind Segue,在 Attributes Inspector 中添加 Segue Identifier。

输入图像描述 输入图像描述

步骤 4 进入需要执行 segue(或关闭 VC)的 VC3,并添加以下内容:

[self performSegueWithIdentifier:@"VC1Segue" sender:self];

嘿!谢谢你的回答。我以前用过取消展开转场,但在这种情况下不是一个选项。为了让问题“简单”,我没有提到的是第二个和第三个视图控制器在一个框架内。所以基本上mainVC在客户端应用程序中,而其他两个则与之分离,在框架中(因此是另一个故事板)。抱歉我没有在问题中提到这一点 :) - rdurand

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接