17

什么对象负责分配UIViewController旋转方法调用,即:

  • shouldAutorotateToInterfaceOrientation:
  • willRotateToInterfaceOrientation:duration:
  • willAnimateFirstHalfOfRotationToInterfaceOrientation:duration:
  • willAnimateSecondHalfOfRotationFromInterfaceOrientation:duration:
  • didRotateFromInterfaceOrientation:

我想它是UIApplication(但可能是 AppDelegate 或 UIWindow)。

下一个问题是对象如何知道与哪个UIViewController对话?

它如何知道哪个UIViewController视图作为窗口的子视图?

是否有您可以发送的消息或您可以设置的(某个对象的)属性来设置UIViewController应用程序的“活动”?

4

4 回答 4

13

似乎UIApplication正在向活动视图控制器发送消息。

但是您的 View Controller 实例是如何获取这些消息的呢?

消息被转发到视图已添加到UIWindow实例的第一个视图控制器。

这归结为3个基本场景:

  1. 视图直接添加到UIWindow 实例的 ViewController(单视图应用程序)

  2. 基于导航的应用程序中的导航控制器,然后导航控制器将消息转发到活动视图视图控制器。

  3. 基于标签栏的应用程序中的标签栏控制器,然后标签栏控制器将消息转发到活动视图视图控制器(或活动导航控制器)。

您将遇到的问题是,如果您构建具有多个视图的应用程序,但不要使用导航控制器或选项卡栏控制器。如果您手动将视图进出UIWindow实例,您将无法可靠地收到这些消息。这类似于这样的帖子: iPhone viewWillAppear not fire

只需将 Apple 的约定用于多个视图,就可以了。希望这可以节省一两个小时

于 2009-02-19T04:49:04.830 回答
4

这都是你永远不用担心的魔法。只需将控制器的根视图添加到窗口中——或者让标签栏或导航控制器为你做这件事——它就会收到这些消息。

(但是,如果您使用调试器四处寻找,您可能会得出与我相同的结论:有某种内部表将每个控制器的视图映射回控制器,并且基于该链接分派消息。)


更新:当我第一次写这个答案时,这在 2009 年是真正的私人魔法,但随后对 iOS 的更改使其背后的 API 公开。现在可以通过该属性访问根视图控制器,并且使用该属性UIWindow.rootViewController形成后代视图控制器的树。UIViewController.childViewControllers

父视图控制器负责将方向更改通知其子级。(我不确定如何通知根视图控制器,但您可以设置一个断点并自行查找。)该-shouldAutomaticallyForwardRotationMethods方法决定 UIViewController 是否会为您执行此操作。如果它返回NO,您将负责在您的-willRotateToInterfaceOrientation:duration:-willAnimateRotationToInterfaceOrientation:duration:-didRotateFromInterfaceOrientation:方法中这样做。

于 2009-02-14T00:42:38.937 回答
4

它如何知道哪个 UIViewController 有它的视图作为窗口的子视图?

UIViewController 类维护视图与其视图控制器之间的静态映射。这张地图在 CocoaTouch 内部的几个关键地方被查询。特别是,[UIView nextResponder] 对其进行查询并在找到时返回控制器。

我猜 UIWindow 对其根视图进行相同的查找,以了解将旋转事件转发到哪个控制器。下次我会在反汇编中查找一些东西时会检查这个。(我花了一些时间对 CocoaTouch 进​​行逆向工程,以了解那里的工作原理。)

于 2009-05-06T11:15:19.790 回答
1

我有一个类似的问题。

我有一个横向工作的游戏(左右横向)。

为了管理多视图应用程序,我使用了一个根 UIviewController,即一个虚拟的 UIViewcontroller 和一个什么都不做的 UIview。然后我将所有其他 UIview 作为子视图添加到它。

启动应用程序时,模拟器会快速旋转到纵向,并且我的每一个视图的 frame 属性看起来都像 (0,-80,320,480)。这导致视图被右侧的 160 X 320 矩形剪裁。

我注意到每个子视图的 – shouldAutorotateToInterfaceOrientation: 方法只调用一次,并且在将其添加到根视图时会发生这种情况。稍后,当旋转设备时,只有根视图会调用它的方法。

不出所料,任何一个 - willAnimate* 方法调用都只会发送到根视图,因此,在子视图中定义这些方法中的任何一个都是没有意义的。

每次将方向更改为 – shouldAutorotateToInterfaceOrientation: 方法接受的方向时,都会调用这些方法。所以我想我可以从那里改变我的子视图的框架属性。

为此,我在 rootViewController 类中定义了以下方法:

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
    subview1_ViewController.view.frame = CGRectMake(0,0,480,320);
    subview2_ViewController.view.frame = CGRectMake(0,0,480,320);
        ...
}

我不明白为什么没有更新 frame 属性,但我知道这种解决方法有效。

希望这可以帮助....

于 2010-03-25T04:20:34.517 回答