iOS 6 UITabBarController支持当前UINavigation控制器的方向。

17

我正在更新一个iPhone应用程序,它在iOS 6上遇到旋转问题。我有一个带有16个UINavigationControllerUITabBarController。大多数子视图可以在纵向或横向工作,但其中一些只能在纵向下工作。在iOS 6中,一些不应该旋转的东西正在旋转。

我尝试通过对tabBarController进行子类化来返回当前navigationController所选viewController的supportedInterfaceOrienations

- (NSUInteger)supportedInterfaceOrientations{

    UINavigationController *navController = (UINavigationController *)self.selectedViewController;
    return [navController.visibleViewController supportedInterfaceOrientations];
}

这让我更接近了解答案。当视图控制器可见时,它不会旋转到错误的位置,但如果我处于横屏状态并切换标签,则新标签将保持横屏状态,即使不支持横屏。

理想情况下,应用程序仅处于当前可见视图控制器的支持方向中。有什么建议吗?

4个回答

58

通过继承UITabBarController并重写以下方法:

-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // You do not need this method if you are not supporting earlier iOS Versions
    return [self.selectedViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}

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

-(BOOL)shouldAutorotate
{
    return YES;
}

继承你的UINavigationController并重写这些方法:

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

-(BOOL)shouldAutorotate
{
    return YES;
}

然后在您不希望旋转的视图控制器中实现这些方法:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

-(BOOL)shouldAutorotate
{
    return NO;
}

-(NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

对于那些希望旋转的视图控制器:

    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
    {
        return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
    }

    -(NSUInteger)supportedInterfaceOrientations
    {
        return UIInterfaceOrientationMaskAllButUpsideDown;
    }

    -(BOOL)shouldAutorotate
    {
        return YES;
    }

你的tabBarController应该被添加为应用程序窗口的根视图控制器。如果你打算支持默认的方向,对于iPhone来说,除了倒立之外都是默认的,那么你不需要做任何其他的事情。如果你想支持倒立或者不想支持其他方向,那么你需要在应用程序代理和/或info.plist中设置适当的值。


7
对我来说,这几乎能够工作。问题是,如果我在横屏模式下,当我切换到纵向视图时,它仍然处于横屏模式。将设备旋转至竖屏模式可以解决此问题,并且它不会再次旋转回到横屏模式,但当它首次加载时,我仍然需要它处于竖屏模式。 - Ryan
我不确定您需要做什么来旋转它,但我敢打赌您可以在-(void)viewWillLayoutSubviews中完成。从记忆中,我可能对该方法名称不是完全正确。当我使用此代码时,我的视图在旋转时会完全改变,我使用该方法将它们重新配置回纵向模式。您也可以尝试在-viewWillDisappear中进行一些操作。也许是[self.view setNeedsDisplay]。我现在不在Xcode上,所以这些只是我在您的情况下要探索的想法。 - Dean Davids
2
我不是在争论这个答案能否有效,但我们不应该需要它。根据苹果的文档,它应该可以直接正常工作。http://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/TabBarControllers.html#//apple_ref/doc/uid/TP40011313-CH3-SW26 - DBD
作为更新 - 一旦我放弃了对iOS5的支持,我就能够删除所有这些代码,除了shouldAutorotate。 - Dean Davids
@Ryan 我有同样的问题。虽然在外观上做出了决定,但是苹果公司的这段代码无法接受。if(UIInterfaceOrientationIsLandscape(self.interfaceOrientation)){ [[UIDevice currentDevice] performSelector:NSSelectorFromString(@"setOrientation:") withObject:(id)UIInterfaceOrientationPortrait]; } - Sergei S
显示剩余2条评论

5

我遇到了一个问题,导航栏中的某些视图控制器支持所有方向,而其他一些只支持竖屏,但是UINavigationController返回了所有应用支持的方向,这个小技巧帮助了我。我不确定这是否是预期行为。

@implementation UINavigationController (iOS6OrientationFix)

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

@end

我不理解那个黑客是如何帮助你在一个导航控制器的不同视图控制器上具有不同的行为。据我所知,这个黑客只会被执行一次,所以所有的视图控制器将与 topViewController 具有相同的旋转行为。难道我漏看了什么吗? - M Penades
1
每当设备改变方向时,此代码将被执行,因此它将返回当前处于活动状态并可见的UIViewController所支持的方向。 - Mindaugas

3
我认为最好使用类别方法(作为一种分类方法)。
-(NSUInteger) supportedInterfaceOrientations {
    if([self.topViewController respondsToSelector:@selector(supportedInterfaceOrientations)])
    {
        return [self.topViewController supportedInterfaceOrientations];
    }
    return UIInterfaceOrientationMaskPortrait;
}

这确保了该方法被实现。如果您不进行此检查而方法未被实现(例如在iOS5环境下),应用程序将崩溃!

0
如果您计划为所有视图控制器启用或禁用旋转,则无需子类化UINavigationController。 相反,请使用:
   -(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window 

在你的AppDelegate中。

如果你计划在你的应用程序中支持所有方向,但是在父级视图控制器(例如UINavigationController堆栈)中使用不同的方向,那么你应该使用

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

通过在您的父视图控制器中与AppDelegate结合使用以下方法。

    - (BOOL)shouldAutorotate

并且

- (NSUInteger)supportedInterfaceOrientations

但是,如果您计划在同一导航堆栈中的不同子视图控制器中具有不同的方向设置(像我一样),则需要检查导航堆栈中的当前视图控制器。

我在我的 UINavigationController 子类中创建了以下内容:

    - (BOOL)shouldAutorotate
{
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations
{
    int interfaceOrientation = 0;

    if (self.viewControllers.count > 0)
    {
        DLog(@"%@", self.viewControllers);
        for (id viewController in self.viewControllers)
        {
            if ([viewController isKindOfClass:([InitialUseViewController class])])
            {
                 interfaceOrientation = UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
            }
            else if ([viewController isKindOfClass:([MainViewController class])])
            {
                 interfaceOrientation = UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown;
            }
            else
            {
                 interfaceOrientation = UIInterfaceOrientationMaskAllButUpsideDown;
            }
        }
    }
    return interfaceOrientation;
}

由于您不能再从子视图控制器中控制所呈现的视图控制器的旋转设置,因此必须以某种方式拦截当前导航堆栈中的视图控制器。这就是我所做的 :)。希望这有所帮助!


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