【问题标题】:UIViewController rotate methodsUIViewController 旋转方法
【发布时间】:2010-10-07 13:58:52
【问题描述】:

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

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

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

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

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

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

【问题讨论】:

  • 问得好,这几天我心里一直有这个疑问。正要问类似的问题,却碰到了这个!
  • 我应该像你一样问我的问题。这些都是与通用问题相关的问题,“自定义框架,阅读文档,现在我应该如何知道它应该如何工作”。

标签: iphone ios cocoa-touch uiviewcontroller


【解决方案1】:

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

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

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

这归结为 3 个基本场景:

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

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

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

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

只需对多个视图使用 Apple 的约定即可。希望这可以节省一两个小时的时间

【讨论】:

  • 一个疑问,导航控制器/标签栏控制器是否将消息传递给子视图的控制器,或者他们只是调整视图的大小?我认为他们只调整子视图的大小,第一个视图控制器不会将消息传递到其视图层次结构中,他们只会调整子视图的大小。
  • 没错,Apple 建议每个屏幕只使用一个 VC。因此不支持使用“子”视图控制器,消息不会自动转发。
  • Corey,如果您有一个应用程序需要在同一屏幕上显示两个表视图,怎么可能将自己限制为每个屏幕一个 VC?每个表视图都需要一个 VC,然后需要一个 VC 来管理它们。或者考虑另一个示例:需要类似标签栏的行为但出于图形/艺术要求的应用程序需要自定义标签栏控制器?对于复杂的 UI,每个屏幕只有一个 VC 似乎是不可行的目标。在这些情况下,必须有某种方法来可靠地控制界面旋转事件?
  • 在我自己的测试中,我发现当嵌套具有不同视图控制器控制它们的视图时,有时哪个视图控制器接收到 shouldAutorotateToInterfaceOrientation 消息是任意的 - 这绝对是不是 i> 总是发送到管理 UIWindow 层次结构的最高子视图的视图控制器 - 它肯定可以发送到对应于该视图控制器视图的子视图的视图控制器。
【解决方案2】:

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

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

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

【讨论】:

    【解决方案3】:

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

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


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

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

    【讨论】:

    • 确实很神奇,+1。根视图控制器旋转和调整大小,子视图的框架根据自动调整大小的掩码进行更改和调整大小。不知道为什么人们对这个可怜的家伙投了反对票!
    • +1,我看不出有理由否决这个答案。遗憾的是,人们不说他们为什么拒绝投票。
    • 当“魔法”不起作用时怎么办?我有一个无法发货的应用程序,因为从未调用过 didRotateFromInterfcaeOrientation: 并且自动调整大小的蒙版无法将视图定位在正确的位置。这是担心它的一个完全正当的理由,这个问题中的任何答案都没有为我解决它 - 所以很明显,它不仅仅是“让一个标签栏为你做这件事”。
    • @AbhiBeckert 几年前我给出了这个答案,当时还没有用于视图控制器层次结构的公共 API。该 API 现在可供任何人使用。查看UIViewController.childViewControllers 和其他视图控制器包含API。他们可能会帮助您找到所需的内容。
    【解决方案4】:

    我也有类似的问题。

    我有一个横向运行的游戏(左右横向)。

    为了管理多视图应用程序,我使用了一个根 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 属性,但我知道这个解决方法有效。

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

    【讨论】:

      猜你喜欢
      • 2011-11-18
      • 1970-01-01
      • 2012-03-27
      • 2011-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多