模态和子视图控制器如何交互?

时间:2013-08-04 20:12:19

标签: ios uiviewcontroller modal-dialog

我有一个自定义容器视图控制器:ContainerVC。它的工作是呈现两个内容视图控制器之一:ContentPortraitVCContentLandscapeVC,具体取决于当前的方向(尽管我认为容器选择其视图的原因并不重要)。 ContentPortraitVC,在某些时候弹出ContentModalDetailVC

因此,有两种不同的方法可以在这里显示新内容:

  • 父母与子女的关系(通过addChildViewController发起并通过removeFromParentViewController删除),

  • 呈现和呈现的关系(通过presentViewController发起并通过dismissViewController删除)。

如果ContainerVC添加了ContentPortraitVC,然后会显示ContentModalDetailVC,然后ContainerVC决定切换到ContentLandscapeVC,{{ 1}}保持可见(为什么在删除父项时不会删除它?)

但是,当要求ContentModalDetailVC删除ContentPortraitVC时,没有任何反应。模态显示保持不变。发生了什么事?

2 个答案:

答案 0 :(得分:5)

  1. 使用addChildViewController添加ContentPortraitVC

    一个。 ContentPortraitVC获取其parentViewController属性集。

    湾然后,您(根据Apple文档)必须手动显示ContentPortraitVC的视图。如果您按照文档操作,则可以将其添加为ControllerVC顶级视图的子级

  2. ContentPortraitVC然后调用presentViewController以显示ContentModalDetailVC

    一个。这将设置其presentingViewController属性(在调试器中显示为_parentModalViewController ivar - 请注意,ivar与属性不同),并设置presentedModalViewController的{​​{1}}属性(谁的ivar是ContentPortraitVC)。

    湾明智地看,在iPhone上,_childModalViewcontroller的视图将完全取代ContentModalDetailVCContentPortraitVC的视图,因此只有模态视图控制器的视图才会可见。 (在iPad上,它将新UI层叠在顶部,但作为ContainerVC视图的兄弟,而ControllerVC的视图又是ContentPortraitVC视图的父级)。

  3. 现在,您从ContentPortraitVC过渡到ContentLandscapeVC

    一个。 IOS有点神奇。它知道您要移除的内容(ContentPortraitVC)当前有presentedViewController个活动,因此它会更改其父级。它将nil上的值设置为ContentPortraitVC,获取子项(ContentModalDetailVC)并将其父项设置为新视图(ContentLandscapeVC)。所以现在呈现模态视图的视图控制器不再是它的呈现视图控制器。就好像ContentLandscapeVC首先提出它一样!

    湾在视图方面,您可以按照Apple文档将视图从ContentPortraitVC更改为ContentLandscapeVC。但您只是更改ControllerVC视图的子视图。在iPhone上,模态视图控制器仍然是唯一显示的内容,因此进行更改不会在屏幕上执行任何操作。在iPad上,确实如此(虽然你可能不会看到它,因为模态视图通常是全屏的)。

  4. 现在你来解雇模态视图。大概是你在ContentPortraitVC中这样做了,但它不再提及它所呈现的东西。因此,调用[self dismissViewController...不会做任何事情,因为ContentPortraitVC不再提供任何内容,对此的责任已转移到ContentLandscapeVC

  5. 这就是发生了什么以及为什么。以下是该怎么做。

    1. 当您从ContentPortraitVC更改为ContentLandscapeVC时,您可以手动重新连接代理,因此后者是尝试关闭模态控制器的代理。

    2. 您可以让模态控制器使用[self dismissModalControllerAnimated:YES completion:nil]解除自身。我将要求并回答另一个问题,为什么这样有效(如果这看起来很奇怪,IOS如何知道解雇哪个?)。

    3. 您可以让ControllerVC成为弹出模态视图的人,并负责删除它。

答案 1 :(得分:2)

如果您检查presentingViewController上的ContentModalDetailVC,您会看到它实际上由ContainerVC而不是ContentPortraitVC呈现。

要解决此问题,您只需在definesPresentationContext上设置ContentPortraitVC(或使用"定义上下文"复选框在Interface Builder中)。

这将告诉ContentPortraitVC处理模式表示,而不是将响应程序链传递给定义表示上下文的下一个视图控制器(默认情况下是根视图控制器)。

您可能希望ContentLandscapeVC定义上下文以避免同样的问题。

当两个子控制器定义自己的表示上下文时,当ContainerVC决定交换子项时,任何模态模态将与呈现它的子项一起从新层次结构中删除。在交换之前不需要做hacky事情试图解雇:)

编辑:我应该补充一点,所呈现的视图控制器必须将modalPresentationStyle设置为currentContextoverCurrentContext