一次解除多个模态视图控制器时的视觉伪像

时间:2015-07-02 22:02:12

标签: ios objective-c uiviewcontroller modalviewcontroller

我一直在努力寻找这个问题的答案。我通过以下方式构建了一堆模态:

[[[NavA viewControllers] objectAtIndex:0] presentViewController:NavB animated:YES completion:NULL];
[[[NavB viewControllers] objectAtIndex:0] presentViewController:NavC animated:YES completion:NULL];

当我想同时解除 NavA NavB 模式时,我会调用

[[[NavA viewControllers] objectAtIndex:0] dismissViewControllerAnimated:YES completion:NULL];

这样可以正常工作,除非有一个简短的闪光,你可以看到 NavB ,因为完整的堆栈被解雇了。

我逐步完成调试器,看起来在动画开始之前 NavC 立即消失, NavB 以动画解散。

有没有办法避免这种视觉效果,并且整个堆栈在动画的整个持续时间内可以通过 NavC 顺畅地解除?

修改:为了澄清,我提出UINavigationController而不是UIViewController,因为此流程适用于用户登录,并且有多个可能的分支,可以返回到现阶段,例如 NavC (LoginPage), NavB (带登录和注册按钮的LandingPage)或一直回到root, NavA (主页应用)。在iOS文档中,它们与摄像机呈现类似的设计模式,其中每个阶段呈现UINavigationController,其中包含多个可能的视图控制器https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ModalViewControllers/ModalViewControllers.html

3 个答案:

答案 0 :(得分:4)

实际上只要使用// Snapshot of "C" ViewController UIGraphicsBeginImageContextWithOptions([UIScreen mainScreen].bounds.size, YES, 0); UIView *snapshot = [self.presentedViewController.view snapshotViewAfterScreenUpdates:NO]; UIGraphicsEndImageContext(); // Cover the entire view of "B" (and hide navigation bar) [self.view addSubview:snapshot]; self.navigationController.navigationBarHidden = YES; // Dismiss "C" without animation [self.presentedViewController dismissViewControllerAnimated:NO completion:^{ // Dismiss "B" with animation [self.presentingViewController dismissViewControllerAnimated:YES completion:nil]; }]; 方法就无法做到这一点,无论你把它放在哪里或者你怎么称呼它(至少我不能,如果有人知道的话 - 我们都想知道)

但是,你可以使用 hack 来达到预期的结果(此代码应该从“B”ViewController调用):

{{1}}

答案 1 :(得分:3)

如果您使用的是故事板,那么使用Unwind Segues可以实现这一点。 Mike Woelmer对此有一个good set of articles。基本上,您向Storyboard提供有关视图如何通过多个不同视图展开以获取已经在堆栈中的视图的信息。

然而,我有点困惑,就像Jeffery Thomas在评论中一样:你为什么要用另一个导航控制器呈现导航控制器?我可以理解您可能希望导航栏在不同视图上看起来不同,但您可以在视图出现时自定义。您应该仔细考虑一下NavB和NavC中的视图内容,并问自己是否应将它们作为模态视图呈现,或者它们是否会作为单个导航堆栈的一部分更好。通过以模态方式呈现每个导航控制器,您最终会得到多个导航堆栈,而不是具有多个视图控制器的单个堆栈。即使只是NavB和NavC是同一堆栈的一部分,它也可能会消除您所看到的视觉故障。

如果您确实使用了单个导航控制器,则可以使用UINavigationController上的方法-popToViewController:animated:返回导航堆栈中的上一个视图控制器。

如果您决定按照当前的模式运行NavB和NavC是正确的事情,那么您可能会遇到麻烦,因为当您要求NavA解除其视图控制器时,它会尝试解除NavB,这意味着在NavB的视图和NavA的视图之间设置过渡。这就是你看到转变的原因,而不是你想要的转变(这是NavC的观点和NavA之间)。可能有效(并且听起来有点奇怪)的一种方法是尝试从NavC呈现NavA,然后覆盖转换,使其看起来像是从堆栈中弹出NavC。一旦你在那里,你可以通过删除对NavB和NavC的任何强引用来清理。 This article from Ash Furrow将帮助您完成大部分工作。

答案 2 :(得分:2)

您可以假装动画完全按照您的意愿制作:

  • 弹出/关闭B和C 不带动画
  • 推送/展示C 不带动画
  • 使用您想要的任何动画来弹出/解除C