I am trying to force only one view in my application on landscape mode, I am calling
override func shouldAutorotate() -> Bool {
print(\"shouldAutoro
I tried many of the answers below but I'm afraid they didn't work. Especially if nav bars and tab bars are also implemented on the app. The solution that worked for me was provided by Sunny Lee on this post here: Sunny Lee, Medium post
Which in turn is an update of this post: Original solution
The only change I made when implementing the post's solution, was to change the part which references .allButUpsideDown to .landscapeleft
I faced a similar issue in my project. It only has support for portrait. The ViewController structure is that, Navigation contained a controller (I called A), and a long Scrollview in A controller. I need A(portrait) present to B(landscape right).
In the beginning I tried the method below and it seemed to work but eventually I found a bug in it.
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
}
And then something become strange. When controller B dismiss to controller A. The ScrollView in controller A has been slid some point.
So I used another method, so I rotate the screen when viewWillAppear
. You can see the code for that below.
// 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
}
Using Swift 2.2
Try:
let value = UIInterfaceOrientation.LandscapeLeft.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")
Followed By:
UIViewController.attemptRotationToDeviceOrientation()
From Apple's UIViewController Class Reference:
Some view controllers may want to use app-specific conditions to determine what interface orientations are supported. If your view controller does this, when those conditions change, your app should call this class method. The system immediately attempts to rotate to the new orientation.
Then, as others have suggested, override the following methods as appropriate:
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.LandscapeLeft
}
override func shouldAutorotate() -> Bool {
return true
}
I was having a similar issue with a signature view and this solved it for me.
Swift 3. This locks the orientation each time the user re-opens the app.
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
}
*/
...
}
Overwrite (in ViewController):
override public var shouldAutorotate: Bool {
return false
}
override public var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .landscapeRight
}
override public var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
return .landscapeRight
}
Hint for ios 13. As of ios 13, VC has different modalPresentationStyle
as .automatic
and device present modal view instead of Full-Screen VC. To fix this one must set modalPresentationStyle
to .fullScreen
. Example:
let viewController = YourViewController()
viewController.modalPresentationStyle = .fullScreen
In Xcode 11 with Swift 5 I Implemented the following. But it only works when the device orientation for the project target does not include all orientations. I disabled the check for Upside Down. After this, the following code works. If all checkboxes are enabled, the code is not called;
class MyController : UINavigationController {
override var shouldAutorotate: Bool {
return true
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .landscape
}
}