当我们执行presentViewController时,底层发生了什么?

14

给定以下代码

self.view.backgroundColor = [UIColor yellowColor];
MyViewController *myVC = [[MyViewController alloc] initWithNibName:@"MyView" bundle:nil]
myVC.view.backgroundColor = [UIColor clearColor];
myVC.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:myVC animated:NO completion:nil];

当我们调用presentViewController时,实际上发生了什么事情?当myVC可见时,我看不到黄色,然后我在它的viewDidAppear方法中检查了myVC.view.superView,并且它是UIWindow。

Q1.这是否意味着,直到模态窗口弹出presentingViewController.view(在上述情况下为self.view)从视图层次结构中删除,并添加presentedViewController.view(在上述情况下为myVC.view)覆盖UIWindow?

Q2.如果myVC.modalPresentationStyle!= UIModalPresentationFullScreen会怎样?

Q3.iOS是否也会删除除了presentedViewController.view之外的所有视图,直到全屏模态对话框弹出以进行优化?如果不是,为什么不是?


clippingVC是什么? - rptwsthi
1个回答

18

首先,让我们讨论没有动画的情况。

在调用present之前:

  1. 您的窗口有一个视图层次结构,从其rootViewController视图开始。

调用present:后:

  1. 视图层次结构仍然存在,没有改变。
  2. 特殊的全屏视图称为“暗示视图”添加到窗口中(即不在rootViewController的视图内而是在窗口内(窗口也是UIView)。该视图是透明的,减弱了呈现控制器并阻止用户交互。
  3. 然后将呈现(模态)控制器的视图也添加到窗口中。

在窗口和呈现控制器窗口之间添加了一些其他视图。如果记录您的视图层次结构,则会看到名称为_ControllerWrapperView或类似名称的类。但是,在iOS版本之间已更改此内容,因此您不应依赖视图结构。 请注意,模态控制器永远不能透明,因为它不是窗口的直接子视图,控制器和窗口之间的包装器不透明。

动画情况几乎相同。只有在步骤之间有一些花哨的动画。

编辑2: 答案实际上有点不正确。iPhone和iPad呈现的控制器之间存在很大差异。

在iPhone上,呈现的控制器始终全屏显示,并且呈现的控制器实际上从窗口中删除。

在iPad上,如果呈现的控制器不是全屏的(请参阅UIModalPresentationStyle),则呈现的控制器将停留在窗口中。

您的问题:

这是意味着直到模态窗口弹出presentingViewController.view(上面的self.view)从View层次结构中删除,并且presentedViewController.view(上面的myVC.view)添加到UIWindow上方吗?

如果控制器是全屏的,则这个说法是正确的。否则,呈现视图控制器仍然存在,但整个内容都被其他视图覆盖(即使它们是半透明的)。此外,在呈现的控制器视图和呈现控制器视图之间总是有一些视图。

如果 myVC.modalPresentationStyle != UIModalPresentationFullScreen 会发生什么情况?

请参见上一个问题的答案 - 在 iPhone 上将没有任何区别。

 

iOS是否也会删除 UIWindow 中除了 presentedViewController.view 以外的所有视图,直到全屏模态对话框弹出以进行优化?如果不是,为什么不这样做?

根据我的测试,只有呈现的控制器从窗口层次结构中删除。这可能是为了优化绘图性能。这是系统可以安全删除的唯一控制器。删除任何其他视图可能会引起问题(例如应始终可见的视图)。

编辑: 如果您想要创建一个透明的控制器,您可以:

  1. 使用过渡动画(+[UIView transition...] )将视图直接添加到您的视图层次结构中(无论是添加到控制器的视图还是添加到窗口)。
  2. 相同的方法,还可以向您的控制器添加子控制器。

2
这个答案有点不正确。当模态全屏控制器被呈现时,UIKit会从窗口中移除其他控制器的视图。实际上,添加/删除到窗口正是 -viewDid/Will(Dis)appear: 方法所报告的内容。但是在你返回它们之前,UIKit会将它们重新添加到窗口中。 - BJ Homer
1
@BJHomer 您是正确的。我主要有iPad的经验,所以在iPhone的情况下我弄错了。已经修正了答案。 - Sulthan
这也是我的实验结果之一 -> “仅从窗口层次结构中删除呈现控制器”。我希望iOS永远不会从窗口层次结构中删除所有其他视图。@BJ Homer错误地说:“当模态全屏控制器被呈现时,UIKit会从窗口中删除其他控制器的视图。” - msk
嗯,我们这样来看。当一个导航控制器推出一个新的控制器时,前一个控制器的视图将从窗口中移除。它仍然存在于内存中,但是被移除了。同样地,当你在一个导航控制器中弹出一个模态控制器时,导航控制器的视图也将从窗口中移除(但仍然在内存中)。不用担心,当呈现的内容再次可见时,它会把它们全部放回去。 - BJ Homer
请注意,我并不是说它会从窗口中删除所有其他视图。它只会完全覆盖被新呈现的内容所知道的控制器拥有的视图。 - BJ Homer
当全屏视图被呈现时,所有的视图控制器(它们的视图)都被完全覆盖,操作系统可以将它们全部移除吗?这是我的第三个问题。 - msk

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