UIViewController旋转方法

时间:2009-02-13 23:50:14

标签: iphone ios cocoa-touch uiviewcontroller

哪个对象负责对UIViewController旋转方法调用进行双重调整,即:

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

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

接下来的问题是,对象如何知道与UIViewController进行对话?

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

是否有可以发送的消息或您可以设置的属性(某个对象)为应用设置“有效”UIViewController

4 个答案:

答案 0 :(得分:13)

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

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

邮件将转发到第一个视图控制器,该视图的视图已添加到UIWindow实例。

这归结为3种基本情景:

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

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

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

  4. 您将遇到的问题是,如果您构建具有多个视图的应用程序,但不要使用导航控制器或Tab Bar控制器。如果您手动交换视图进出UIWindow实例,则不会可靠地接收这些消息。 这类似于这样的帖子: iPhone viewWillAppear not firing

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

答案 1 :(得分:4)

这就是你永远不会担心的魔法。只需将控制器的根视图添加到窗口中 - 或者让标签栏或导航控制器为您执行此操作 - 它将收到这些消息。

(但是如果你使用调试器,你可能得出相同的结论:有一些内部表将每个控制器的视图映射回控制器,并根据该链接调度消息。)< / p>


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

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

答案 2 :(得分:4)

  

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

UIViewController类在视图及其视图控制器之间维护静态映射。在CocoaTouch内的几个关键位置查询此映射。特别是,[UIView nextResponder]查询它并返回控制器(如果找到)。

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

答案 3 :(得分:1)

我有类似的问题。

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

为了管理多视图应用程序,我使用了一个根UIviewController,即一个虚拟的UIView控制器,其UIview不执行任何操作。然后我将其他所有UIview作为子视图添加到其中。

启动应用程序时,模拟器会快速旋转到纵向,我的每个视图的框架属性看起来都像(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属性没有更新,但我知道这个解决方法有效。

希望这会有所帮助......