Restrict/Force 使用 UITabBarController 时只有一些视图控制器指向特定方向 and/or UINavigationController

Restrict/Force only some view controllers to specific orientations when using UITabBarController and/or UINavigationController

我在网上到处搜索,但找不到关于此的明确答案。当一个 UIViewController 嵌入 UINavigationController 中时,只有一个 UIViewController 支持横向模式的最佳方法是什么?UINavigationController

大多数解决方案,like this one,建议覆盖

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

AppDelegate。这有点工作,但是当从唯一支持横向模式的 ViewController 返回时,所有其他(非横向 ViewControllers)也将处于横向。他们不保持纵向。

我已经看到应用程序可以做到这一点,所以我知道这一定是可行的。例如,电影播放器​​应用程序通常是纵向的,但实际的电影播放器​​视图是在强制横向模式下模态呈现的。关闭模态 viewcontroller 后,底层 viewcontroller 仍然正确地处于纵向,

有什么提示吗?

你应该把上面的代码写到UINavigationController子类中。您应该使用 if 语句定义您的应用程序方向并分离您的视图控制器方向。

-(BOOL)shouldAutorotate {

    if ([[self.viewControllers lastObject] isKindOfClass:[UIViewController class]] ) {

        return [[self.viewControllers lastObject] shouldAutorotate];
    }

    return NO;

}
- (NSUInteger)supportedInterfaceOrientations {

    if ([[self.viewControllers lastObject] isKindOfClass:[UIViewController class]]) {

        return [[self.viewControllers lastObject] supportedInterfaceOrientations];
    }

    return UIInterfaceOrientationMaskPortrait;
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {


    return UIInterfaceOrientationPortrait;

}

这是我经过 大量 研究后得出的结论:

首先,我尝试实施

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

在 AppDelegate 中,如 here 所述,适用于大多数情况。但是除了感觉相当 "hacky" 之外,还有一个严重的问题:模态显示视图控制器的解决方法(参见 "A small problem with modal controllers" 部分)在例如显示 AVPlayerViewController 时失效,因为它实现了它自己的 dismiss 方法,你不能挂钩它来设置 self.isPresented(不幸的是,viewWillDisappear: 来不及了)。

所以我采用了另一种方法,将 sub类 用于 UITabBarControllerUINavigationController,感觉更简洁,只是稍微冗长一点:

CustomNavigationController

CustomNavigationController.h

#import <UIKit/UIKit.h>

@interface CustomNavigationController : UINavigationController

@end

CustomNavigationController.m

#import "CustomNavigationController.h"

@implementation CustomNavigationController

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

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

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return [self.topViewController preferredInterfaceOrientationForPresentation];
}

@end

CustomTabBarController

CustomTabBarController.h

#import <UIKit/UIKit.h>

@interface CustomTabBarController : UITabBarController

@end

CustomTabBarController.m

#import "CustomTabBarController.h"

@implementation CustomTabBarController

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

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

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return [self.selectedViewController preferredInterfaceOrientationForPresentation];
}

@end

之后只需将以下代码添加到您的 UIViewControllers:

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
    // Presents the `UIViewController` in landscape orientation when it is first displayed 
    return UIInterfaceOrientationLandscapeLeft;
}

- (NSUInteger)supportedInterfaceOrientations {
    // Allows all other orientations (except upside-down)
    return UIInterfaceOrientationMaskAllButUpsideDown;
}

现在您可以在每个视图控制器的基础上决定首选和支持的方向。请注意,我没有在我的视图控制器中实现 shouldAutorotate 因为它默认为 YES,如果你的视图控制器应该被强制到某个方向(是的,它们应该自动旋转到唯一支持的方向),这就是你想要的.

调用链是这样的:

  • CustomTabBarController,即 window 的 rootViewController,被要求supported/preferred 方向
  • CustomTabBarController依次询问它的selectedViewController(当前选中的tab的view controller),正好是我的CustomNavigationController
  • CustomNavigationController询问嵌入的topViewController,这最终是实际UIViewController实现上述方法

您仍然需要在构建目标中允许所有设备方向。当然,您需要更新 storyboards/xibs/classes 以使用这些子 类 而不是标准 UINavigationControllerUITabBarController 类.

这种方法的唯一缺点是,至少在我的情况下,我必须将这些方法添加到我的视图控制器的 所有 中,以使大多数视图控制器仅显示纵向和一些景观能力。但恕我直言,这绝对值得!