6

更新:先看看我对这个问题的回答。这似乎是一个错误。已经创建了一个最小的测试用例,并向 Apple 提交了一份报告。(自 iPhone OS 3.1 起已修复。)

这是来自“我是如此接近!”的谜题。部。

我有一个基于标签栏的 iPhone 应用程序。每个选项卡都有一个UINavigationController与通常的嫌疑人(导航栏,表格视图......这反过来又可以导致另一个 VC 等)。

现在,这些较低级别的 VC 之一将用于纵向横向模式。但是有一个问题。我们的景观友好型 VC 的shouldAutorotateToInterfaceOrientation:不会被直接调用!该怎么办?

这就是我们所做的。在我在自己的文件中实现的标签栏控制器中,我有这个:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
     return [self.selectedViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}

这最终将请求传播到我的景观友好型 VC,它也响应此消息。我所有的其他 VC 都没有实现这个方法,所以他们只是使用默认的纵向。

问题解决了!!!耶!

嗯,不完全是。:(

当从标签栏控制器的MoreNavigationController的深处调用我的风景友好型 VC 时,事情似乎不太顺利。

我决定比较/对比从前四个选项卡栏UINavigationControllers之一调用的VC ... 和从MoreNavigationController调用的同一个 VC 。这将有点超详细,所以请耐心等待。希望逐场比赛证明对侦查事情很有用。

当应用程序加载时,有几个对标签栏控制器的 shouldAutorotate... 方法的初始调用。在这些早期情况下,selectedViewController为 nil。但是,我们最终加载完成,选择了初始选项卡项,一切正常。

对。首先,让我们选择前四个标签栏项目之一并深入到我们的 VC。

我们将选择第三个导航栏项目,这就是第三个导航控制器。我们深入了解支持轮换的 VC。快速检查确认父级确实是我们标签栏的视图控制器列表中的第三个导航控制器。好的!

让我们旋转设备。标签栏控制器被要求自动旋转(参见上面的代码)。我们观察到selectedViewController也是第三个导航控制器,加上导航控制器的顶部和可见视图控制器都设置为我们可信赖的支持旋转的 VC。

因此,标签栏控制器会将shouldAutorotate消息转发给第三个导航控制器……但我们的旋转友好型 VC 最终会收到该消息。(我在这里没有做任何特别的事情。也许所需的 VC 会收到消息,因为它是顶部和/或可见的 VC?)无论如何,我们旋转到横向,调整大小,一切都很好。“巨大的成功!”

现在让我们点击后退按钮并弹出 VC 堆栈,在此过程中保留横向模式。再次查询标签栏控制器。

是时候在这里稍作休息了。我们的导航控制器的topViewController仍然是旋转友好的 VC,但是visibleViewController现在设置为UISnapshotModalViewController!呵呵。以前从未见过这个……但Erica Sadun 有。看起来它是用于“消失的视图控制器”(在这种情况下肯定是真的 - 它消失了)。

当我继续前进时,可见的 VC 保持为快照,但顶部的 VC 最终会更改为堆栈中的下一个 VC,因为我的特殊 VC 最终消失了。很公平。

所以就是一切正常的场景。

现在让我们尝试相同的测试,只是这次我们将转到MoreNavigationController(更多选项卡栏项)并向下钻取到与之前相同的 VC 类。在我的例子中,它恰好是标签栏控制器的 VC 列表中的第 7 个。

我们进入旋转感知 VC 并且......这次它被要求直接旋转!根本不要求标签栏控制器获得旋转权限。唔。

快速检查父 VC 显示它是一个MoreNavigationController。好的,这是有道理的。

现在让我们尝试旋转设备。什么都没有被调用。我们的断点都没有被命中。不在我们的 VC 中。不在我们的标签栏控制器中。(咦?!?!)

好的。让我们弹出堆栈,回到同一个 VC 并再次尝试旋转。奇怪的。现在我们在标签栏控制器中接到一个请求自动旋转权限的电话。在这里,选择的控制器是我们信任的导航控制器(#7),但这次它的visibleViewControllertopViewController设置为NIL

一旦我们从这里继续,调试器控制台中会出现一条神秘消息:

使用两阶段旋转动画。要使用更平滑的单阶段动画,此应用程序必须删除两阶段方法实现。

神秘,因为我没有使用两阶段旋转动画!在我的源代码中的任何地方都没有SecondHalf方法变体。

唉,我的旋转感知 VC 从来没有被告知旋转正在发生(即使旋转确实发生在屏幕上),所以我的观点当然被弄乱了。混乱和悲伤随之而来。:(

在这一点上,我们甚至不会费心弹出堆栈。

我认为 View Controller 文档暗示了可能的问题:

如果您想在方向更改期间执行自定义动画,您可以通过以下两种方式之一进行。方向更改过去分两步发生,通知发生在旋转的开始点、中间点和结束点。但是,在 iPhone OS 3.0 中,添加了对一步执行方向更改的支持。使用一步方向更改往往比旧的两步过程更快,通常建议用于任何新代码。

我想知道MoreNavigationController是否仍在响应两步过程,因此是否会阻止任何使用一步过程的尝试?请注意,如果您回复两步消息,则一步变体将不起作用(同样,根据文档)。我没有回应他们,但我有一个偷偷摸摸的怀疑是幕后的东西。

事实上,如果我注释掉单步方法,并尝试响应willAnimateSecondHalfOfRotationFromInterfaceOrientation:duration:,我确实得到了备忘录!但它仍然不能非常干净地从堆栈中弹出(就视觉效果而言)。更奇怪的是:willAnimateFirstHalfOfRotationFromInterfaceOrientation:duration:没有被调用,即使我试图在 shouldAutorotateToInterfaceOrientation: 中偷偷调用 self (使用 FirstHalf 消息。它在跟踪期间立即返回,就好像我从未定义过它一样。叹。

所以这就是逐场比赛。

总而言之,有没有成功地处理了从标签栏控制器的 MoreNavigationController 中调用的 VC 的一步设备旋转?求知者想知道!

4

3 回答 3

7

Apple 建议不要将 UITabBarController 子类化,因此我找到了一种使用类别来处理自动旋转的简单方法。它不能使用 More... 视图控制器修复您的错误,但我认为这是一种更适合 Apple 的完成工作的方式(并且意味着您的子类化更少)。

为了使我的应用程序中的每个选项卡都能正确自动旋转,我在我的自定义视图控制器中定义了 -shouldAutorotateToInterfaceOrientation:,但它们都在 UITabBarController 内的 UINavigationControllers 内,因此在这两个之前,消息不会沿着链发送到我的 VC也回应。所以我在我的应用程序委托文件中添加了以下几行:

添加到 MyAppDelegate.h 的底部

@interface UITabBarController (MyApp)
@end

@interface UINavigationController (MyApp)
@end

添加到 MyAppDelegate.m 的底部

@implementation UITabBarController (MyApp) 
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    return YES;
}
@end

@implementation UINavigationController (MyApp) 
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    return YES;
}
@end
于 2010-02-05T01:44:44.867 回答
3

看来我们有一个错误。我创建了一个可重现的最小测试用例,并通过 Apple Bug Reporter 报告(RADAR 问题 7139857)。

更新:这已从 iPhone OS 3.1 开始修复。

本质问题是:

当使用标签栏控制器的“更多导航控制器”时,导航控制器堆栈上的视图控制器不会收到 willAnimateRotationToInterfaceOrientation:duration:消息。

当标签栏项目视图控制器是基本视图控制器时,不会发生此问题。仅当它们是导航控制器并且当使用“更多”导航层次结构时。

控制台消息(关于两阶段旋转动画)表明框架内的某些东西(更多导航控制器?)仍在使用两阶段动画,尽管现在从 iPhone OS 3.0 开始建议使用单阶段动画。

这可以解释为什么willAnimateRotationToInterfaceOrientation:在这种特殊情况下没有被调用。根据 Apple 的视图控制器文档,当响应两阶段、第一/后半方向消息时,不会调用此消息。

于 2009-08-13T13:23:36.267 回答
0

Victorb 答案的略微修改版本,它允许每个视图控制器决定是否允许旋转。

这里作为更容易复制和分叉的要点

AppDelegate.h

@interface UITabBarController (MyApp)
@end

@interface UINavigationController (MyApp)
@end

AppDelegate.m

@implementation UITabBarController (MyApp) 
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    UIViewController *selectedVC = [self selectedViewController];
    if ([selectedVC respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) {
        return [selectedVC shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
    }

    //optimistic return - if you want no rotation, you have to specifically tell me!
    return YES;
}
@end

@implementation UINavigationController (MyApp) 
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    UIViewController *visibleVC = [self visibleViewController];
    if ([visibleVC respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) {
        return [visibleVC shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
    }

    //optimistic return - if you want no rotation, you have to specifically tell me!
    return YES;
}
@end
于 2012-06-26T04:12:08.943 回答