在导航控制器中禁用视图控制器的旋转

Posted

技术标签:

【中文标题】在导航控制器中禁用视图控制器的旋转【英文标题】:Disable rotation for View Controller in Navigation Controller 【发布时间】:2014-01-19 12:12:21 【问题描述】:

首先,这不是重复的。我已经在 SO 上查看了与此相关的所有问题,但没有一个对我有用。希望这只是因为我是 ios 开发的新手,但我怀疑这在我的情况下是不可能的。我附上了一张我想要禁用旋转的视图控制器的图片。

我已经尝试过:子类化我想要禁用旋转的视图控制器,并通过将其设置为 NO 来使用 shouldAutoRotate 方法。显然这不起作用,因为导航控制器决定了它的视图控制器是否可以旋转。所以,我将UINavigationController 子类化并在故事板中使用这个类而不是默认的导航控制器。在这堂课中,我将shouldAutoRotate 设置为 NO。它仍然不起作用。真的不知道我做错了什么。

当我使用我的视图控制器类扩展根视图控制器并将shouldAutoRotate 设置为 NO 时,它会禁用旋转...对于整个应用程序。这不是我想要的。我只想为图片中圈出的视图控制器禁用旋转。

提前致谢!

【问题讨论】:

这在不同的解决方案中被多次回答,但对于您的情况,答案也是相同的。查看我的答案了解更多详情。 【参考方案1】:

添加您的 AppDelegate.h

@property (nonatomic , assign) bool blockRotation;

AppDelegate.m

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

if (self.blockRotation) 
    return UIInterfaceOrientationMaskPortrait;

return UIInterfaceOrientationMaskAll;

在要禁用旋转的视图控制器中

- (void)viewDidLoad

 [super viewDidLoad];
    AppDelegate* shared=[UIApplication sharedApplication].delegate;
    shared.blockRotation=YES;


-(void)viewWillDisappear:(BOOL)animated
  AppDelegate* shared=[UIApplication sharedApplication].delegate;
  shared.blockRotation=NO;

  

Swift 4.2 及更高版本:

在您的 AppDelegate.swift 中:

var blockRotation = false

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask 
    if blockRotation 
        return .portrait
    
    return .all

在您的视图控制器中:

override func viewDidLoad() 
    super.viewDidLoad()
    AppDelegate.shared.blockRotation = true


override func viewWillDisappear(_ animated: Bool) 
    super.viewWillDisappear(animated)
    AppDelegate.shared.blockRotation = false

【讨论】:

即使它看起来像 hack,它也为我解决了问题。只有当您在另一个 ViewController 可见时转动设备时,ViewController 才会继续转动。只是一句话:在您的 AppDelegate 中,您将其称为 blockRotation,但在 ViewController 中称为 allowRotation 小备注此作品不适用于 iPad/iOS 10,在项目设置中设置 Require full screen 为 YES。【参考方案2】:

感谢@ozgur 为我提供的修复。我会“投票”,但显然我还不够好(无论如何!)投票修复是否有效。无论如何,它在 Swift 中:

在 AppDelegate.swift 中:

class AppDelegate: UIResponder, UIApplicationDelegate 


var blockRotation: Bool = false

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int 

    if (self.blockRotation) 
        println("supportedInterfaceOrientations - PORTRAIT")
        return Int(UIInterfaceOrientationMask.Portrait.rawValue)
     else 
        println("supportedInterfaceOrientations - ALL")
        return Int(UIInterfaceOrientationMask.All.rawValue)
    

在要阻止旋转的 ViewController 中,将 UIApplicationDelegate 添加到您的类...

class LoginViewController: UIViewController, UITextFieldDelegate, UIApplicationDelegate 

然后创建对 AppDelegate 的引用...

var appDelegate = UIApplication.sharedApplication().delegate as AppDelegate

在viewDidLoad中,设置appDelegate.blockRotation = true:

override func viewDidLoad() 
    super.viewDidLoad()

    // Do any additional setup after loading the view.

    appDelegate.blockRotation = true


在 viewWillAppear 中,设置方向以强制设备为所选方向(本例中为纵向):

override func viewWillAppear(animated: Bool) 

    let value = UIInterfaceOrientation.Portrait.rawValue
    UIDevice.currentDevice().setValue(value, forKey: "orientation")


然后在viewWillDisappear中,或者在prepareForSegue中,设置appDelegate.blockRotation = false:

override func viewWillDisappear(animated: Bool) 
    appDelegate.blockRotation = false

在阅读了本网站上的其他解决方案数小时后,这对我来说在这个确切的(导航控制器中的多个视图控制器)场景中很有用。再次感谢@ozgur - 如果可以的话,我会投票给your answer!

旅途愉快!

【讨论】:

您好。很好的答案!你的回答是唯一对我有帮助的。然而,我想知道一件事。在模拟器中,一旦 blockRotation 更改,内容不会自动旋转,它仍然需要将虚拟设备更改为横向,然后才能锁定到正确的方向。你知道我怎样才能强制内容变为横向吗?谢谢! 嗨@Stew - E. 非常感谢。我花了几个小时才弄清楚这一点,所以我很高兴它也为您节省了一些时间。关于强制旋转,我没有尝试过,但您可以在 viedDidAppear 中尝试以下操作:let value = UIInterfaceOrientation.LandscapeLeft.rawValueUIDevice.currentDevice().setValue(value, forKey: "orientation") 也适用于 viewWillAppear 你不需要实现UIApplicationDelegate 或任何东西。只需使用(UIApplication.sharedApplication().delegate as! AppDelegate). blockRotation = true【参考方案3】:

您必须检查您的根视图控制器是否允许在当前顶部控制器中旋转,并在 supportedInterfaceOrientations 方法中返回 YES 或 NO。所以它应该类似于根控制器中的以下代码(根据您的情况调整代码):

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

然后在每个视图控制器中添加支持的界面方向,例如:

- (NSUInteger)supportedInterfaceOrientations

    return UIInterfaceOrientationMaskPortrait;

【讨论】:

当我将该代码放入我的根视图控制器时,即使我将supportedInterfaceOrientations 放入代码中,它也会禁用每个视图控制器的旋转。有什么想法吗? 您的目标是将支持的轮换决策委托给特定控制器。我相信您在supportedInterfaceOrientation 中的代码应该如下所示: return [.navigationController.topViewController supportedInterfaceOrientations]; 好的,在我的根视图控制器中,我有 - (NSUInteger)supportedInterfaceOrientations return [self.navigationController.topViewController supportedInterfaceOrientations];在 DashboardViewController 我有 - - (NSUInteger)supportedInterfaceOrientations return UIInterfaceOrientationMaskLandscape;问题是,即使视图控制器中的这个方法被调用,它仍然停留在纵向,即使我说 UIInterfaceOrientationMaskLandscape; 我不知道你项目中VC的层次结构,你能告诉我如何访问根视图控制器中当前可见的DashboardViewController吗? 好的。正如您在图片中看到的,我有一个幻灯片菜单根视图控制器。然后进入菜单视图控制器,从那里,每个菜单项都有一个导航控制器。所以每个单独的菜单选项都有自己的导航控制器。我使用 return self.navigationController.topViewController.【参考方案4】:

对于那些使用 Swift 2 的人,您可以按照 Andre 的回答进行操作,但在第一步中,请在您的 AppDelegate.swift 中使用以下代码:

class AppDelegate: UIResponder, UIApplicationDelegate 


var blockRotation: Bool = false

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask 

    if (self.blockRotation) 
        print("supportedInterfaceOrientations - PORTRAIT")
        return UIInterfaceOrientationMask.Portrait
     else 
        print("supportedInterfaceOrientations - ALL")
        return UIInterfaceOrientationMask.All
    

supportedInterfaceOrientationsForWindow:现在返回 UIInterfaceOrientationMask 而不是 Int。

【讨论】:

【参考方案5】:

我的案例有 3 个视图控制器: - 第一个视图控制器:纵向 - 第二个视图控制器:横向右侧(具有导航控制器并由第一个视图控制器呈现) - 第三个视图控制器:纵向(具有导航控制器并由第二个视图控制器推送) 这是我在 swift 3 中的解决方案: ------------------------------------ 在 AppDelegate: - 添加此属性以保存您的设置

private var orientation: UIInterfaceOrientationMask = .portrait

-然后创建一个函数来为您的设备设置旋转:

func rotateScreen(orientation: UIInterfaceOrientationMask) 
    self.orientation = orientation
    var value = 0;
    if orientation == .landscapeRight 
        value = UIInterfaceOrientation.landscapeRight.rawValue
    else 
        value = UIInterfaceOrientation.portrait.rawValue
    
    UIDevice.current.setValue(value, forKey: "orientation")

- 最后,实现支撑定位方法:

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask 
    return self.orientation

-------------------------------- 然后你可以在显示目标视图控制器之前这样调用

(UIApplication.shared.delegate as! AppDelegate).rotateScreen(orientation: .landscapeRight)

例如,在我的例子中:当用户点击第一个按钮以呈现第二个时,我会这样做

(UIApplication.shared.delegate as! AppDelegate).rotateScreen(orientation: .landscapeRight)
self.present(navigation, animated: true, completion: nil)

第二个的关闭按钮我会这样做

(UIApplication.shared.delegate as! AppDelegate).rotateScreen(orientation: .portrait)
self.dismiss(animated: true, completion: nil)

就是这样!您永远不会介意使用导航控制器。 希望对大家有所帮助^__^!

【讨论】:

【参考方案6】:

UINavigationController+Rotation Category

当您使用导航控制器 SupportedInterfaceOrientaionsViewController 将无法工作时,将此类别添加到您的项目将也从您的 viewController 获得响应,而不是单独的 NavigationController

【讨论】:

这不起作用。这与您描述的情况不同,这就是它不起作用的原因。【参考方案7】:

在我的情况下,我将视图控制器嵌入到导航控制器中,并且大多数解决方案都不起作用,因为视图控制器取决于导航控制器的方向。为此,当您创建视图控制器的实例时,您必须将其强制转换为 UINavigationController :

    let theViewController = UIViewController()
    if let navController = theViewController as? UINavigationController 
        navController.delegate = self
    

然后添加这个扩展: 扩展 PlaySplashViewController: UINavigationControllerDelegate

func navigationControllerSupportedInterfaceOrientations(_ navigationController: UINavigationController) -> UIInterfaceOrientationMask 
    return UIInterfaceOrientationMask.portrait

在这种情况下,这将为导航控制器设置纵向方向,因此视图控制器也将使用此方向。

【讨论】:

以上是关于在导航控制器中禁用视图控制器的旋转的主要内容,如果未能解决你的问题,请参考以下文章

iPhone 6 Plus 上的拆分视图控制器旋转

在视图控制器中重置导航栏的外观

UINavigationController 的子视图中调用的旋转方法?

在导航控制器顶部控制器之间滚动

禁用导航栏的动画

禁用转场动画