iOS 6中的自动旋转功能表现奇怪

28

我有一个使用 UITabBarController 的应用程序,可以播放视频并在其他的 UITabBar 标签中显示其他信息。在iOS 6中,UIView 的旋转方法已经被弃用,现在需要使用 shouldAutoRotatesupportedInterfaceOrientations 方法。对于视频播放,我使用 MPMoviePlayerViewController

如何仅旋转该播放器视图?我只能旋转整个应用程序,但不想这样做。我呈现了 MPMoviePlayerViewController,但它不像在 iOS 5 及之前版本中那样旋转。

plist 设置中,我只设置了1个纵向界面方向。如果我设置其他方向,则整个应用程序将会旋转。

7个回答

45

以下翻译为苹果iOS 6 SDK发布说明中的内容:

iOS 6中的自动旋转功能发生了变化。在iOS 6中, UIViewController的 shouldAutorotateToInterfaceOrientation: 方法已被弃用。取而代之的是,您应该使用 supportedInterfaceOrientationsForWindow: 和 shouldAutorotate 方法。

更多的责任转移到了应用程序和应用程序委托。现在,iOS容器(例如UINavigationController)不再查看其子项以决定它们是否应该自动旋转。默认情况下,针对iPad采用 UIInterfaceOrientationMaskAll,针对iPhone采用UIInterfaceOrientationMaskAllButUpsideDown 来设置应用程序和视图控制器的支持界面方向。

一个视图控制器的支持界面方向可以随时间改变 - 即使应用程序的支持界面方向也可以随时间改变。每当设备旋转或每当视图控制器以全屏模态呈现样式呈现时,系统都会向最顶层的全屏视图控制器(通常是根视图控制器)询问其支持的界面方向。此外,仅当此视图控制器从其 shouldAutorotate 方法返回 YES 时,才会检索支持的方向。 系统将视图控制器的支持方向与应用程序的支持方向(由Info.plist文件或应用程序委托的application:supportedInterfaceOrientationsForWindow: 方法确定)相交,以确定是否进行旋转。

系统通过将应用程序的 supportedInterfaceOrientationsForWindow: 方法返回的值与最顶层全屏控制器的 supportedInterfaceOrientations 方法返回的值相交来确定是否支持某个方向。 setStatusBarOrientation:animated: 方法并没有被完全弃用。只有在最顶层全屏视图控制器的 supportedInterfaceOrientations 方法返回0时,它才能起作用。这使得调用者负责确保状态栏方向是一致的。

为了兼容性,仍然实现 shouldAutorotateToInterfaceOrientation: 方法的视图控制器不会获得新的自动旋转行为。(换句话说,它们不会回退到使用应用程序、应用程序委托或 Info.plist 文件来确定支持的方向。)相反,shouldAutorotateToInterfaceOrientation: 方法用于合成将由 supportedInterfaceOrientations 方法返回的信息。

如果您想让整个应用程序旋转,则应将Info.plist设置为支持所有方向。现在,如果您想让特定视图仅为竖屏,则需要创建某种子类并重写自动旋转方法以仅返回竖屏。我这里有一个例子: https://dev59.com/b2cs5IYBdhLWcg3w3HoG#12522119

您还可以根据设备指定方向。例如,在iPad上允许特定的旋转,但将iPhone的方向锁定。 - Andrew Kozlik

13

哎呀!半天时间用掉了,问题解决了!嘿嘿。

正如上面的文档所说,这就是真正的问题所在!核心要点是:

更多的责任正在转移到应用程序和应用程序代理。现在,iOS容器(例如UINavigationController)不会向它们的子项查询是否应该自动旋转屏幕。默认情况下,iPad设备和iPhone设备支持的界面方向设置为UIInterfaceOrientationMaskAll和UIInterfaceOrientationMaskAllButUpsideDown。

因此,每当具有根控制器的内容发生更改时,系统都会询问应用程序代理“那么,我们怎么样?旋转还是不旋转?”

如果“旋转”:

只有在此视图控制器从其shouldAutorotate方法返回YES时,才会检索支持的方向

然后系统会向我们的应用程序代理提出问题:

- (NSUInteger) application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {    

    return ...;
}

那真的非常简单。

何时允许使用竖屏或横屏等 - 取决于您。测试根控制器对我来说行不通,因为存在某些问题,但是这个方法有效:

- (NSUInteger) application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {    

    return self.fullScreenVideoIsPlaying ?
        UIInterfaceOrientationMaskAllButUpsideDown :
        UIInterfaceOrientationMaskPortrait;
}

每当我需要时,我手动设置"fullScreenVideoIsPlaying"属性。

唯一需要注意的是枚举类型,正如文档中所说明的...(仔细阅读上面iPad/iPhone的内容)。因此,您可以根据需要进行更改。

另一个小问题是在关闭播放器控制器后出现了一些错误行为。有一次它没有更改方向,但这种情况只发生了一次,并且以某种奇怪的方式,在模拟器中发生(当然只在iOS 6中)。所以,我甚至无法做出反应,因为它发生得出乎意料,而在我快速点击我的应用程序中的其他元素后,它恢复到正常方向。所以,不确定-可能是模拟器工作中的某些延迟或其他原因(或者确实是一个错误:))。

祝你好运!


哦!我刚才忘了。相对于方向,我没有在我的plist文件中做任何更改!我只允许其中的竖屏模式! - Agat
1
嗨!我做了完全相同的事情,但是不同的是,在解除横向视图控制器后,它不会将方向改回纵向模式...我可能忘记了什么吗?你能提供一个简单的示例项目吗? - cldrr
抱歉,我没有看到有关评论的通知... 我没有单独的代码,但似乎您错过了一些小细节。您是否也实现了这个方法?: - (BOOL)shouldAutorotate 因为文档中说:“_此外,仅当此视图控制器从其shouldAutorotate方法返回YES时,才检索支持的方向._” - Agat
优秀的解决方案。使用self.fullScreenVideoIsPlaying来检测是否应该旋转屏幕是解决我的问题的关键。 - AndyDunn

7

我曾经也遇到过我的应用程序出现了相同的问题。

iOS 6中旋转的工作原理如下:

=> 只要您正在使用UINavigationCOntroller,就会在AppDelegate中使用该方法。

- (NSUInteger) application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window    
{
   return 
}

决定是否进行旋转。
=> 当视图以模态呈现样式呈现时,该方法。
- (BOOL)shouldAutorotate

当视图控制器中的方法触发时,它会调用appDelegate中的方法。如果是第一种情况,appDelegate会决定是否旋转。

我的解决方案:

对于模态呈现,我创建了一个标志在appDelegate中。

每当标志为YES时,它会旋转到横向,否则仅为纵向。

- (NSUInteger)application:(UIApplication*)application
supportedInterfaceOrientationsForWindow:(UIWindow*)window
{
    if(self.shouldRotate ) //shouldRotate is my flag
    {
        self.shouldRotate = NO;
        return (UIInterfaceOrientationMaskAll);
    }
    return (UIInterfaceOrientationMaskPortrait);
}

同时可以在旋转之间切换

- (BOOL)shouldAutorotate
{
    YourAppDelegate *mainDelegate = (YourAppDelegate*)[[UIApplication sharedApplication]delegate];
    mainDelegate.shouldRotate = YES;

    return YES;
}

注意:此方法仅适用于以模型形式呈现的视图。使用标志并不是一个好的编码实践。


确保在关闭模态视图控制器时,重新设置shouldRotate = NO; - Manu
使用标志并不被视为最佳实践,但它是一个相当不错的工作解决方案。 - ArtSabintsev

3
你也可以通过子类化UITabBarController,使其向其子视图查询shouldAutorotate和supportedInterfaceOrientation,代码如下:
@implementation MyTabBarController

-(BOOL)shouldAutorotate
{
    return [self.selectedViewController shouldAutorotate];
}

-(NSUInteger)supportedInterfaceOrientations
{
    return [self.selectedViewController supportedInterfaceOrientations];
}

@end

然后你只需在标准容器的位置使用您的自定义容器即可,它就可以工作了!我刚刚测试过。


2
很遗憾,您需要在plist中打开所有方向,并在除了视频播放器之外的所有视图控制器上使用supportedInterfaceOrientations来禁止旋转。(在您的情况下,除了视频播放器以外的所有内容都需要这样做。)

1
这在某种程度上是正确的(并且对我有效)...但是通过阅读http://fostah.com/ios/2012/09/27/ios6-orientation-handling.html,显然可以仅将plist设置为支持纵向模式,然后在应用程序委托中实现supportedInterfaceOrientationsForWindow方法。 在我的情况下,我需要所有方向的电影播放器视图,但其余部分是纵向的。 - cclogg

1

请尝试以下方法:

如果TabBarController是窗口的根视图控制器, 那么创建一个自定义类,继承TabBarController,称为CustomTabBarController.h。

在CustomTabBarController.h中添加以下方法:

-(NSUInteger)supportedInterfaceOrientations // Must return Orientation Mask

最后在AppDelegate.m中调用以下代码。
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window  {
   if( [self.window.rootViewController supportedInterfaceOrientations]!=0) 
     {
        return [self.window.rootViewController supportedInterfaceOrientations];
    }
    return UIInterfaceOrientationMaskAll;
}

0
我发现设置这个最简单的方法是使用“支持的界面方向”按钮,您可以在 Targets....Summary 选项卡(iPhone/iPad 部署信息下)看到它们。
基本上它是一个用于设置 plist 文件的图形用户界面。

是的。我发现这是解决在iOS 6上开发的应用程序在iOS 5上旋转问题最快的方法。我可能应该多说一点。谢谢。 - Tim

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