使用Swift在一个ViewController中强制使用横向模式


74

我试图在横向模式下仅强制应用程序中的一个视图,

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

override func supportedInterfaceOrientations() -> Int {
    print("supportedInterfaceOrientations")
    return Int(UIInterfaceOrientationMask.LandscapeLeft.rawValue)
}

override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
    return UIInterfaceOrientation.LandscapeLeft
}

该视图以纵向模式启动,并且在我更改设备方向时保持旋转。
从不调用shouldAutorotate。
任何帮助,将不胜感激。



Answers:


82

它对其他人可能有用,我找到了一种强制视图以横向模式启动的方法:

把它放在viewDidLoad()中:

let value = UIInterfaceOrientation.landscapeLeft.rawValue
UIDevice.current.setValue(value, forKey: "orientation")

和,

override var shouldAutorotate: Bool {
    return true
}

5
我只是尝试使用它,但是没有用;虽然更改了shouldAutorotate()以返回false仍然有效。只是要清楚一点:无论如何,我希望它保留在Portrait中。(也将
UIInterfaceOrientation.LandscapeLeft

2
这是因为您的视图在“纵向”模式下加载,并且希望它保持原样,我的视图在“纵向”模式下加载,并且希望它在“横向”模式下显示。如果我将shouldAutorotate设置为NO,它将不会在Landscape中显示
Sazz

谢谢!!这对我使用Swift 2.2强制肖像的iOS9应用程序非常有用。我从横向的“父”视图开始,将上面的代码放在ViewController的viewDidLoad中,从“父”以模态形式呈现,当呈现模态视图时,该视图旋转为纵向。当我关闭模态视图时,“父级”保持纵向(尽管我敢打赌,您可以在显示模态之前存储“以前的方向”值,然后将“父级”视图重新设置为以前的方向,如果您想随意使用它!
纳塔利娅

3
这会导致Apple拒绝您的应用程序吗?方向是一个只读属性,您正在操纵该值。我认为苹果会对此感到皱眉。
pulse4life

1
仅通过覆盖shouldAutorotate在iOS 14,Swift 5.3上为我工作。
夸克

61

斯威夫特4

override func viewDidLoad() {
    super.viewDidLoad()
    let value = UIInterfaceOrientation.landscapeLeft.rawValue
    UIDevice.current.setValue(value, forKey: "orientation")
}

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return .landscapeLeft
}

override var shouldAutorotate: Bool {
    return true
}

如果您的视图嵌入在导航控制器中,则仅靠上述方法是行不通的。您必须在类定义之后通过以下扩展进行级联。

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
    }
}}


迅捷3

override func viewDidLoad() {
    super.viewDidLoad()
    let value = UIInterfaceOrientation.landscapeLeft.rawValue
    UIDevice.current.setValue(value, forKey: "orientation")
}

private func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.landscapeLeft
}

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

3
此代码在iOS 12上不起作用。应用程序崩溃并显示错误,例如“支持的方向与应用程序没有共同的方向,[PlayerViewController shouldAutorotate]返回YES”
Mayur Ra​​thod

@MayurRathod您找到了崩溃的解决方法。
Shirish

@Shirish是的,我在委托文件中实现了方向更改代码
Mayur Ra​​thod

@MayurRathod如果您有时间,请发表您的答案
Mark

该解决方案在iPhone上运行良好,但在iPad中使用了演示控制器,因此整个应用程序都面向横向。知道我哪里错了吗?
user550088 '04

29

Swift 4,在iOS 11中测试

您可以在projectTarget-> General-> DeploymentInfo(Device Orientation)-> Portrait中指定方向(Landscapeleft和Landscaperight是可选的)

AppDelegate

    var myOrientation: UIInterfaceOrientationMask = .portrait
    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        return myOrientation
    }

LandScpaeViewController

override func viewDidLoad() {
        super.viewDidLoad()
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        appDelegate.myOrientation = .landscape
}

OnDismissButtonTap

let appDelegate = UIApplication.shared.delegate as! AppDelegate
 appDelegate.myOrientation = .portrait

而已。:)


2
仅当设备旋转一次时,才会调用supportedInterfaceOrientationsFor。
娜迦·马拉什

这就是我一直在寻找的东西,谢谢!对于任何想知道差异的人,这将在没有动画的情况下以旋转方式呈现新视图。在UIDevice上设置方向时,将添加默认的旋转动画。
PostCodeism

21

使用Swift 2.2

尝试:

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

其次是:

UIViewController.attemptRotationToDeviceOrientation()

从Apple的UIViewController类参考中:

一些视图控制器可能希望使用特定于应用程序的条件来确定支持哪些界面方向。如果您的视图控制器执行此操作,则当这些条件发生变化时,您的应用应调用此类方法。系统立即尝试旋转到新方向。

然后,按照其他人的建议,适当覆盖以下方法:

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

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

我在签名视图中遇到了类似的问题,这为我解决了这一问题。


1
感谢您的回答,此注释>UIViewController.attemptRotationToDeviceOrientation()非常重要,因为有时控制器不知道是否要执行旋转。但这告诉它相应地执行旋转。
Ramandeep Singh Gosal

18

对我而言,最好的结果是结合Zeesha的答案和sazz的答案。

将以下行添加到AppDelegate.swift:

var orientationLock = UIInterfaceOrientationMask.portrait
var myOrientation: UIInterfaceOrientationMask = .portrait
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return myOrientation
}  

将以下行添加到您的视图控制器类:

let appDel = UIApplication.shared.delegate as! AppDelegate

将以下行添加到视图控制器的中viewDidLoad()

appDel.myOrientation = .landscape
UIDevice.current.setValue(UIInterfaceOrientation.landscapeLeft.rawValue, forKey: "orientation")

(可选)将此行添加到您的关闭功能:

appDel.myOrientation = .portrait
UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")

这些代码行的作用是将默认方向设置为纵向,在加载视图控制器时将其横向旋转,然后在视图控制器关闭后最终将其重置为纵向。


3
这也对我有用,因为在我的项目->部署信息中,我只是选择了肖像模式。谢谢
Dasoga '18

1
这些年来,我尝试了许多方法。到目前为止,这是最简单的解决方案,无需在所有堆叠的控制器上进行迭代。希望它能持续
下去

11

在AppDelegate中添加以下内容:

//Orientation Variables
var myOrientation: UIInterfaceOrientationMask = .portrait

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return myOrientation  
}

将其添加到要更改方向的viewController中:

override func viewDidLoad() {
        super.viewDidLoad()
        self.rotateToLandsScapeDevice()
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        self.rotateToPotraitScapeDevice()
    }

    func rotateToLandsScapeDevice(){
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        appDelegate.myOrientation = .landscapeLeft
        UIDevice.current.setValue(UIInterfaceOrientation.landscapeLeft.rawValue, forKey: "orientation")
        UIView.setAnimationsEnabled(true)
    }

    func rotateToPotraitScapeDevice(){
        let appDelegate = UIApplication.shared.delegate as! AppDelegate
        appDelegate.myOrientation = .portrait
        UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
        UIView.setAnimationsEnabled(true)
    }

1
即使在两年半之后,它仍然像魅力一样工作。谢谢。
OnurŞahindur19年

完美的解决方案!
nitin.agam

任何人遇到此解决方案的错误?如果我旋转到横向,则使用“应用程序任务管理器”在设备上选择其他应用程序,然后导航回我的应用程序,然后单击“返回”。方向保持在横向。
Grantespo

7

我需要强制一个控制器进入纵向。添加它对我有用。

使用iOS 11的Swift 4

override var   supportedInterfaceOrientations : UIInterfaceOrientationMask{

    return  .portrait

}

4

覆盖(在ViewController中):

override public var shouldAutorotate: Bool {
    return false
} 

override public var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return .landscapeRight
}

override public var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
    return .landscapeRight
}

提示为IOS 13. IOS 13,VC具有不同modalPresentationStyle作为.automatic和装置本模态的视图,而不是全屏幕VC。要解决此问题,必须将其设置modalPresentationStyle.fullScreen。例:

let viewController = YourViewController()
viewController.modalPresentationStyle = .fullScreen

viewController.modalPresentationStyle = .fullScreen帮助了我。谢谢!
anoo_radha

2

在Swift 2.2中工作

 func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
    if self.window?.rootViewController?.presentedViewController is SignatureViewController {

        let secondController = self.window!.rootViewController!.presentedViewController as! SignatureViewController

        if secondController.isPresented {

            return UIInterfaceOrientationMask.LandscapeLeft;

        } else {

            return UIInterfaceOrientationMask.Portrait;
        }

    } else {

        return UIInterfaceOrientationMask.Portrait;
    }
}

上面的代码是在AppDelegate中还是在您要强制肖像的ViewController中?
纳塔利娅

2

Swift3。每次用户重新打开应用程序时,这会锁定方向。

class MyViewController: UIViewController {
    ...
    override func viewDidLoad() {
        super.viewDidLoad()

        // Receive notification when app is brought to foreground
        NotificationCenter.default.addObserver(self, selector: #selector(self.onDidBecomeActive), name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil)
    }

    // Handle notification
    func onDidBecomeActive() {
        setOrientationLandscape()
    }

    // Change orientation to landscape
    private func setOrientationLandscape() {
        if !UIDevice.current.orientation.isLandscape {
            let value = UIInterfaceOrientation.landscapeLeft.rawValue
            UIDevice.current.setValue(value, forKey:"orientation")
            UIViewController.attemptRotationToDeviceOrientation()
        }
    }

    // Only allow landscape left
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return UIInterfaceOrientationMask.landscapeLeft
    }

    /*
    // Allow rotation - this seems unnecessary
    private func shouldAutoRotate() -> Bool {
        return true
    }
    */
    ...
}

2

斯威夫特4

试图保持方向无济于事,但这对我来说:

...        
override func viewDidLoad() {
       super.viewDidLoad()
       forcelandscapeRight()
       let notificationCenter = NotificationCenter.default
       notificationCenter.addObserver(self, selector: #selector(forcelandscapeRight), name: Notification.Name.UIDeviceOrientationDidChange, object: nil)
    }

    @objc func forcelandscapeRight() {
        let value = UIInterfaceOrientation.landscapeRight.rawValue
        UIDevice.current.setValue(value, forKey: "orientation")
    }
....

2

在ViewController中的viewDidLoad方法下面的函数调用

func rotateDevice(){
    UIDevice.current.setValue(UIInterfaceOrientation.landscapeLeft.rawValue, forKey: "orientation")
    UIView.setAnimationsEnabled(true) // while rotating device it will perform the rotation animation
}`

App委托文件在函数和变量下方添加

//Orientation Variables
var orientationLock = UIInterfaceOrientationMask.portrait
var myOrientation: UIInterfaceOrientationMask = .portrait

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { return .landscape }


0

我的解决方案是

刚刚在AppDelegate中添加了以下代码

enum PossibleOrientations {
  case portrait
    case landscape

    func o() -> UIInterfaceOrientationMask {
      switch self {
      case .portrait:
        return .portrait
      case .landscape:
        return .landscapeRight
      }
    }
}
var orientation: UIInterfaceOrientationMask = .portrait

func switchOrientation(to: PossibleOrientations) {
    let keyOrientation = "orientation"

    if to == .portrait && UIDevice.current.orientation.isPortrait {
        return
    } else if to == .landscape && UIDevice.current.orientation.isLandscape {
        return
    }

    switch to {
    case .portrait:
        orientation = .portrait
        UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: keyOrientation)
    case .landscape:
        orientation = .landscapeRight
        UIDevice.current.setValue(UIInterfaceOrientation.landscapeRight.rawValue, forKey: keyOrientation)
    }
}

并调用以下代码进行更改

override func viewDidLoad() {
    super.viewDidLoad()

    if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
        appDelegate.switchOrientation(to: .landscape)
    }
}

或像下面

@IBAction func actBack() {
    if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
        appDelegate.switchOrientation(to: .portrait)
    }
    self.navigationController?.popViewController(animated: true)
}

0
// below code put in view controller
// you can change landscapeLeft or portrait

override func viewWillAppear(_ animated: Bool) {
        UIDevice.current.setValue(UIInterfaceOrientation.landscapeRight.rawValue, forKey: "orientation")
    }

override var shouldAutorotate: Bool {
        return true
    }
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .landscapeRight
    }
    override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
        return .landscapeRight
    }

0

我在项目中遇到了类似的问题。它仅支持人像。ViewController的结构是,Navigation包含一个控制器(我称为A)和一个A控制器中的长Scrollview。我需要给B(风景右侧)展示A(人像)。

一开始,我尝试了以下方法,该方法似乎可行,但最终我发现了一个错误。

Swift 5和iOS12

// In B controller just override three properties

override var shouldAutorotate: Bool {
    return false
}

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return UIInterfaceOrientationMask.landscapeRight
}

override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
    return .landscapeRight
}

然后,事情变得奇怪了。当控制器B向控制器A撤消时。控制器A中的ScrollView已滑到某个点。

因此,我使用了另一种方法,所以当时旋转屏幕viewWillAppear。您可以在下面查看代码。

// In controller B
// not need override shouldAutorotate , supportedInterfaceOrientations , preferredInterfaceOrientationForPresentation

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    let appDel = UIApplication.shared.delegate as! AppDelegate
    appDel.currentOrientation = .landscapeRight
    UIDevice.current.setValue( UIInterfaceOrientation.landscapeRight.rawValue, forKey: "orientation")
    UIViewController.attemptRotationToDeviceOrientation()
}

//in viewWillDisappear rotate to portrait can not fix the bug


override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
    let appDel = UIApplication.shared.delegate as! AppDelegate
    appDel.currentOrientation = .portrait
    UIDevice.current.setValue( UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
    UIViewController.attemptRotationToDeviceOrientation() //must call 
    super.dismiss(animated: true, completion: nil)
}
// in AppDelegate
// the info plist is only supported portrait also, No need to change it

var currentOrientation : UIInterfaceOrientationMask = .portrait


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

单击按钮后,您可以在更改方向上创建任何示例/演示吗?
Chandan Jee

0

我尝试了以下许多答案,但恐怕它们没有用。特别是如果导航栏和标签栏也已在应用程序上实现。Sunny Lee在此职位上提供了对我有用的解决方案: Sunny Lee,中等职位

这又是该帖子的更新: 原始解决方案

实现该帖子的解决方案时,我所做的唯一更改是将引用.allButUpsideDown的部分更改为.landscapeleft


0

在带有Swift 5的Xcode 11中,我实现了以下内容。但是,仅当项目目标的设备方向未包括所有方向时,该方法才有效。我禁用了“颠倒”检查。在此之后,以下代码起作用。如果启用了所有复选框,则不调用该代码;否则,将不调用该代码。

class MyController : UINavigationController {

    override var shouldAutorotate: Bool {
        return true
    }

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return .landscape
    }


}

-3
class CustomUIViewController : UIViewController{

    override var   supportedInterfaceOrientations : UIInterfaceOrientationMask{

        return  .landscapeLeft

    }

}


class ViewController: CustomUIViewController {
.
.
.
}

欢迎堆栈溢出,如何在此处正确编写答案检查。
拉胡尔·夏尔玛
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.