在Swift iOS中设置设备方向

67

我正在开发一款iPhone的Swift应用程序。在我的应用中有一个模态视图,我只想让它在竖屏模式下显示。

我的问题是,如何通过编程来强制手机不允许旋转?换句话说,我正在寻找一段代码,它将不允许模态视图以横向模式显示(打开竖向旋转锁定)。

这仅适用于一个模态视图,因此我无法关闭整个应用程序的旋转,否则我只会完全禁用旋转。

我在研究中发现了一些代码在这里,但它是Objective-C,如果有帮助的话。谢谢!


这是一个解决您问题及相关问题的答案:http://stackoverflow.com/questions/37983846/changing-orientations-programatically-does-not-work-fine/43054291#43054291 - Ariel Antonio Fundora
17个回答

71

对于横向左右方向 (更新 Swift 2.0)

enter image description here 并且在信息中有这个

enter image description here

和 UIController

override func shouldAutorotate() -> Bool {
    return true
}

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return [UIInterfaceOrientationMask.LandscapeLeft,UIInterfaceOrientationMask.LandscapeRight]
}

对于PortraitUpsideDown和Portrait使用以下设置: 输入图像描述

override func shouldAutorotate() -> Bool {
    if (UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeLeft ||
        UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeRight ||
        UIDevice.currentDevice().orientation == UIDeviceOrientation.Unknown) {
            return false
    }
    else {
        return true
    }
}

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return [UIInterfaceOrientationMask.Portrait ,UIInterfaceOrientationMask.PortraitUpsideDown]
}

其他解决方案:

extension UINavigationController {
    public override func shouldAutorotate() -> Bool {
        if visibleViewController is MyViewController {
            return true   // rotation
        } else {
            return false  // no rotation
        }
    }
    
    public override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        return (visibleViewController?.supportedInterfaceOrientations())!
    }
}

在信息中找到了iPad方向的好方法。 - Phil Hudson
@dark-_-d0g,在最后一个语句中,第一条语句不应该是true,第二条语句不应该是false吗?也许是复制粘贴的错误... - Juan Boero
我认为对于纵向视图和UIDeviceOrientation.Unknown情况下,应该Rotate()函数应该返回true。在我的测试中,如果iPad在启动应用程序时处于横向模式,则应用程序会保持在此模式下。 - Dmitry Yudakov

52
您可以将以下方法粘贴到需要纵向显示的每个视图的ViewController中:
override func shouldAutorotate() -> Bool {
    return false
}

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.Portrait
}

13
如果设备在呼叫模态视图时处于横向模式,则此代码无法正常工作。在这种情况下,模态视图会以横向模式显示,并且无法旋转。我该怎么办?谢谢您的答案,如果我们能解决这个问题,我会接受它。 - rocket101
2
编辑为将 UIInterfaceOrientation 强制转换为 Int。它是一个 UInt 值,当前版本的 Swift 现在需要进行强制转换。 - Bill Weinman
4
我不相信这个方法适用于在导航控制器中有一个VC的情况,如果你只想让它应用于一个VC而不是所有VC。 - deebs
7
应该使用 UIInterfaceOrientationMask 而不是 UIInterfaceOrientation - redent84
3
shouldAutorotate() 方法中,你应该返回 true - AydinAngouti
显示剩余6条评论

43

Swift 3

如果视图控制器嵌入了UINavigationController或UITabBarController中,则方向旋转会更加复杂,导航栏或选项卡栏控制器会优先并决定自动旋转和支持的方向。

使用以下扩展程序在UINavigationController和UITabBarController上,以便嵌入在这些控制器之一中的视图控制器可以做出决策:

UINavigationController扩展程序

extension UINavigationController {

override open var shouldAutorotate: Bool {
    get {
        if let visibleVC = visibleViewController {
            return visibleVC.shouldAutorotate
        }
        return super.shouldAutorotate
    }
}

override open var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation{
    get {
        if let visibleVC = visibleViewController {
            return visibleVC.preferredInterfaceOrientationForPresentation
        }
        return super.preferredInterfaceOrientationForPresentation
    }
}

override open var supportedInterfaceOrientations: UIInterfaceOrientationMask{
    get {
        if let visibleVC = visibleViewController {
            return visibleVC.supportedInterfaceOrientations
        }
        return super.supportedInterfaceOrientations
    }
 }}

UITabBarController扩展

extension UITabBarController {

override open var shouldAutorotate: Bool {
    get {
        if let selectedVC = selectedViewController{
            return selectedVC.shouldAutorotate
        }
        return super.shouldAutorotate
    }
}

override open var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation{
    get {
        if let selectedVC = selectedViewController{
            return selectedVC.preferredInterfaceOrientationForPresentation
        }
        return super.preferredInterfaceOrientationForPresentation
    }
}

override open var supportedInterfaceOrientations: UIInterfaceOrientationMask{
    get {
        if let selectedVC = selectedViewController{
            return selectedVC.supportedInterfaceOrientations
        }
        return super.supportedInterfaceOrientations
    }
}}

现在您可以在要锁定的视图控制器中覆盖supportedInterfaceOrientations、shouldAutoRotate和preferredInterfaceOrientationForPresentation,否则您可以在其他视图控制器中省略这些覆盖项,以继承应用程序plist中指定的默认方向行为。

锁定特定方向

class YourViewController: UIViewController {
open override var supportedInterfaceOrientations: UIInterfaceOrientationMask{
    get {
        return .portrait
    }
}}

禁用旋转

    class YourViewController: UIViewController {
open override var shouldAutorotate: Bool {
    get {
        return false
    }
}}

更改首选界面方向以进行演示

class YourViewController: UIViewController {
open override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation{
    get {
        return .portrait
    }
}}

它在Swift 4上无法工作,显示“override' can only be specified on class members”。 - Shikha Budhiraja

18

由于您的视图控制器可能属于导航控制器,以上代码可能无法正常工作。如果是,则即使它具有不同的方向规则,它也必须遵守导航控制器的规则。更好的方法是让视图控制器自行决定,而导航控制器将使用顶部视图控制器的决策。

我们可以通过此UINavigationController通用扩展来支持锁定当前方向并自动旋转以在特定方向上锁定:

extension UINavigationController {
            public override func shouldAutorotate() -> Bool {
                return visibleViewController.shouldAutorotate()
            }

        public override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
            return (visibleViewController?.supportedInterfaceOrientations())!
        }
    }

现在在您的视图控制器中,我们可以

class ViewController: UIViewController {
    // MARK: Autoroate configuration

    override func shouldAutorotate() -> Bool {
        if (UIDevice.currentDevice().orientation == UIDeviceOrientation.Portrait ||
            UIDevice.currentDevice().orientation == UIDeviceOrientation.PortraitUpsideDown ||
            UIDevice.currentDevice().orientation == UIDeviceOrientation.Unknown) {
                return true
        }
        else {
            return false
        }
    }

    override func supportedInterfaceOrientations() -> Int {
        return Int(UIInterfaceOrientationMask.Portrait.rawValue) | Int(UIInterfaceOrientationMask.PortraitUpsideDown.rawValue)
    }
}

希望能对你有所帮助。 谢谢。


我相信你是对的!但是...我创建了一个navigationController的swift文件并将其放在扩展中。我添加了print语句并发现它仅在第一次调用时被调用。正常的屏幕之间的移动不会调用扩展中的函数。 - user462990
嗨@Vivek,我使用了你的代码,它正常工作。但是我不明白为什么我的一些视图控制器在旋转,而另一些却没有。你有任何想法吗? - Ramakrishna

11

这将禁用视图的自动旋转:

override func shouldAutorotate() -> Bool {
    return false;
}

更新

override func shouldAutorotate() -> Bool {
    if (UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeLeft ||
        UIDevice.currentDevice().orientation == UIDeviceOrientation.LandscapeRight ||
        UIDevice.currentDevice().orientation == UIDeviceOrientation.Unknown) {
            return false;
    }
    else {
        return true;
    }
}
如果应用程序处于横向模式,并且您显示必须以纵向模式显示的视图,则这将允许应用程序更改其方向为纵向(当设备旋转到该方向时)。

11

如果有人需要答案,我想我刚得到它。尝试这个:

  • 转到您的 .plist 文件并检查所有方向。
  • 在您想要强制方向的视图控制器中添加以下代码:
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.Portrait.toRaw().hashValue | UIInterfaceOrientationMask.PortraitUpsideDown.toRaw().hashValue
}

希望能有所帮助!

编辑:

要强制旋转,请使用以下代码:

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

它适用于iOS 7和8!


1
我不得不用“.rawValue”替换“.toRaw()”。但对我来说仍然无效 :/ - deebs
1
UIDevice.currentDevice().setValue(value, forKey: "orientation") 很可能会导致您的应用在App Store被拒绝。您不允许像这样设置设备的方向。 - emresancaktar
当我们设置设备的方向键时,我们不应该使用 UIInterfaceOrientation 枚举,而应该使用 UIDeviceOrientation 枚举吗?因为这两个枚举值不同,混淆它们可能是危险的。 - vcattin
那么正确的做法是什么?我需要在用户点击按钮时旋转屏幕方向。 - user7097242
不起作用;错误:无法分配给属性:'orientation'是只读属性。 - Corbin Miller

9

enter image description here

Go to your pList and add or remove the following as per your requirement:

"Supported Interface Orientations" - Array
"Portrait (bottom home button)" - String
"Portrait (top home button)" - String
"Supported Interface Orientations (iPad)" - Array
"Portrait (bottom home button)" - String
"Portrait (top home button)" - String
"Landscape (left home button)" - String
"Landscape (right home button)" - String

注意:这种方法允许整个应用程序旋转。
或者
为项目中的UIViewController创建一个ParentViewController(继承方法)。
//  UIappViewController.swift

import UIKit

class UIappViewController: UIViewController {
          super.viewDidLoad()   
    }
//Making methods to lock Device orientation.
    override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        return UIInterfaceOrientationMask.Portrait
    }
    override func shouldAutorotate() -> Bool {
        return false
    }                                                                                                                                       
    override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            // Dispose of any resources that can be recreated.
        }
    }

将每个视图控制器的父控制器关联为UIappViewController。
//  LoginViewController.swift

import UIKit
import Foundation

class LoginViewController: UIappViewController{

    override func viewDidLoad()
    {
        super.viewDidLoad()

    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

8

针对Swift 3和iOS 10

override open var shouldAutorotate: Bool {
    return false
}

override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return .portrait
}

override open var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
    return .portrait
}

然而,在当前iOS 9版本中,shouldAutorotate设置存在一个bug,无法正常工作。


6
在info.plist文件中,更改您想要的方向在“支持的界面方向”中。
在Swift中,支持文件的方式是-> info.plist->支持接口方向。

4
我整个上午一直在努力地让左右横屏的支持正常工作。我发现了一个非常恼人的问题:虽然“常规”选项卡允许您取消设备方向的“纵向”,但您必须编辑plist文件本身才能禁用“纵向”和“倒置的纵向”接口方向 - 这是plist中的最后一个键:“支持的接口方向”。
另外一件事是,似乎你必须使用枚举的“mask”版本(例如UIInterfaceOrientationMask.LandscapeLeft),而不仅仅是方向。让它为我工作的代码(在我的主视图控制器中):
override func shouldAutorotate() -> Bool {
    return true
}

override func supportedInterfaceOrientations() -> Int {
    return Int(UIInterfaceOrientationMask.LandscapeLeft.rawValue) | Int(UIInterfaceOrientationMask.LandscapeRight.rawValue)
}

我只有通过修改plist文件和代码的结合才能使其正常工作。


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