关闭堆栈中较低的 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
将在客户端应用程序中,而secondVC
和thirdVC
在我的框架中,在单独的故事板中。除了在我的代码中引用它之外,我无法以任何其他方式访问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是不是在较低的堆栈端下方提供了保证的不可访问的内存区域?