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

Posted

技术标签:

【中文标题】关闭堆栈中较低的 ViewController 的行为不符合预期【英文标题】:Dismissing a ViewController lower in the stack does not behave as expected 【发布时间】:2014-09-24 13:00:02 【问题描述】:

我正在构建一个中间有一个分支的复杂应用程序。

在应用程序的某个时刻,会出现一个特定的 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];

这样,我直接在mainVC 上调用dismissViewControllerAnimated:(由self.presentingViewController.presentingViewController 引用),我希望thirdVC 会被动画解除,而secondVC 会消失没有动画。

正如 Apple 在 UIViewController 类文档中所说:

呈现视图控制器负责关闭视图 它呈现的控制器。如果您在呈现的视图上调用此方法 控制器本身,它会自动将消息转发到 呈现视图控制器。

如果你连续呈现多个视图控制器,从而构建一个 呈现的视图控制器堆栈,在视图上调用此方法 堆栈中较低的控制器关闭其直接子视图 控制器和堆栈上该子级上方的所有视图控制器。 发生这种情况时,只有最顶层的视图会在动画中消失 时尚;任何中间视图控制器都被简单地从 堆。最顶层的视图使用其模态转换被关闭 样式,可能与其他视图控制器使用的样式不同 在堆栈中较低。

问题在于,事情并非如此。在我的场景中,thirdVC 消失了,并显示 secondVC 被经典的模态滑动到底部动画解散。

我做错了什么?


编辑:

所以@codeFi 的答案可能是在一个经典项目中工作,但这里的问题是我正在研究一个框架。所以mainVC 将在客户端应用程序中,而secondVCthirdVC 在我的框架中,在单独的故事板中。除了在我的代码中引用它之外,我无法以任何其他方式访问mainVC,因此不幸的是,这里不是一个选项。

【问题讨论】:

这种行为变化发生在 ios 8 中,在 7 中它确实可以正常工作。我现在正在尝试解决它。​​ @theLastNightTrain :好吧,你是对的,它只发生在 iOS 8 上。如果你有任何发现,请告诉我。 @theLastNightTrain:有什么更新吗?我很高兴为解决这个问题的答案提供赏金.. 抱歉,不,就我而言,我已经尽可能地解决了这个问题。我注意到关闭动画会有所帮助,但并不完美,这意味着您无法获得标准动画。 【参考方案1】:

我一直遇到同样的问题,我设法通过将屏幕快照作为子视图添加到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];

【讨论】:

似乎工作得很好。在他们修复它之前会很好。谢谢! 请注意,如果您的secondVC 有导航栏,您需要在截屏和将快照作为子视图添加到secondVC 之间隐藏导航栏,否则快照将出现在导航栏下方,因此在解雇动画期间似乎显示了双导航栏。 感谢您的建议,将其直接添加到您的答案中可能会很有用。对我来说,两个 ViewController 上的状态栏都是隐藏的,所以没问题 :)【参考方案2】:

我遇到了同样的问题,我已经使用 UnwindSegues 修复了它。

基本上,您所要做的就是在您想要继续的 ViewController 中添加一个 IBAction Unwind Segue 方法,然后在 IB 中将 Exit 操作连接到您的 Unwind Segue 方法。

例子:

假设您有三个 ViewController(VC1、VC2、VC3)并且您想从 VC3 转到 VC1。

第 1 步 向 VC1 添加一个方法,如下所示:

- (IBAction)unwindToVC1:(UIStoryboardSegue*)sender


第 2 步 进入 Interface Builder 到 VC3 并选择它。然后按住 CTRL 键从您的 VC 图标拖动到 Exit 图标并选择您刚刚在 VC1 中添加的方法。

第 3 步 在 IB 中并选择 VC3 时,选择您的 Unwind Segue 并在 Attributes Inspector 中添加一个 Segue Identifier。

第 4 步 转到需要执行 segue(或关闭 VC)的 VC3 并添加以下内容:

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

【讨论】:

嘿!感谢您的回答。我过去曾使用过 unwind segues,但在这种情况下它们不是一个选项。为了让问题保持“简单”,我没有提到第二个和第三个视图控制器位于框架内。所以基本上 mainVC 在客户端的应用程序中,另外两个在框架中与它分开(因此是另一个故事板)。很抱歉没有说这个我的问题:)

以上是关于关闭堆栈中较低的 ViewController 的行为不符合预期的主要内容,如果未能解决你的问题,请参考以下文章

如果堆栈在数字较低的地址处增长,为啥指针比较会反转呢?

linux是不是在较低的堆栈端下方提供了保证的不可访问的内存区域?

带有dismissViewControllerAnimated的iOS 8错误:完成:动画?

MySQL查找先前值较低的峰值? [关闭]

选择给定条件的行

firestore firebase storage 以较低的分辨率检索图像