Programmatically lock iDevice orientation - ios

In an app we are developing we have an option to let the user choose preferred orientation (i.e if they choose Portrait the app will be locked to portrait orientation and the same for Landscape and if Both is opted the app will work on all orientation) I am sharing the code for what I have tried, and I'm not sure whether this functionality is feasible at all.
//MARK:- ORIENTATION
func changeOrientation(orientation: String) {
switch orientation {
case "Portrait":
UserDefaults.standard.set("Portrait", forKey: UserDefaultsKeys.preferredOrientation)
appDelegate.preferredOrientation = "Portrait"
let value = UIInterfaceOrientation.portrait.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
break
case "Landscape":
UserDefaults.standard.set("Landscape", forKey: UserDefaultsKeys.preferredOrientation)
appDelegate.preferredOrientation = "Landscape"
let value = UIInterfaceOrientation.landscapeLeft.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
break
default:
UserDefaults.standard.set("Both", forKey: UserDefaultsKeys.preferredOrientation)
appDelegate.preferredOrientation = "Both"
break
}
/*not necessary*/
let vc = UIViewController()
UIViewController.attemptRotationToDeviceOrientation()//forces to rotate
/*not necessary*/
self.present(vc, animated: false, completion: nil)
UIView.animate(withDuration: 0.3, animations: {
vc.dismiss(animated: false, completion: nil)
})
/*not necessary*/
}
open override var supportedInterfaceOrientations: UIInterfaceOrientationMask{
get {
switch appDelegate.preferredOrientation {
case "Portrait":
return .portrait
case "Landscape":
return .landscape
default:
return .all
}
}
}
open override var shouldAutorotate: Bool {
get {
return true
}
}
However if I choose 'Landscape' when in portrait mode, it automatically switches to landscape. But, if I rotate the device back to portrait it is working as well (which shouldn't be working as per the requirement). The requirement is similar to what happens when we setup project only with Portrait mode and how it will behave when the device is rotated to landscape mode.

I just wrote a sample project to test if this is possible. Well, I think it is! Unfortunately
UIViewController.attemptRotationToDeviceOrientation()
does not do the job magically how I hope so - it is a little bit more complex than that.
Please take a loot at the following code. All the magic you need is happening in the action forceChangeOrientations.
class ViewController: UIViewController {
enum Orientation {
case Landscape
case Portrait
mutating func changeOrientation() {
if self == .Portrait {
self = .Landscape
}
else {
self = .Portrait
}
}
func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
switch self {
case .Landscape:
return .Landscape
case .Portrait:
return .Portrait
}
}
func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
switch self {
case .Landscape:
return UIInterfaceOrientation.LandscapeLeft
case .Portrait:
return .Portrait
}
}
}
var currentOrientation: Orientation = .Portrait
// Returns a Boolean value indicating whether the view controller's contents should auto rotate.
override func shouldAutorotate() -> Bool {
return true
}
// Returns all of the interface orientations that the view controller supports.
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return currentOrientation.supportedInterfaceOrientations() //UIInterfaceOrientationMask.All
}
// Returns the interface orientation to use when presenting the view controller.
override func preferredInterfaceOrientationForPresentation() -> UIInterfaceOrientation {
return UIInterfaceOrientation.Portrait
}
#IBAction func forceChangeOrientations(sender: AnyObject) {
self.currentOrientation.changeOrientation()
let value = self.currentOrientation.preferredInterfaceOrientationForPresentation().rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")
UIViewController.attemptRotationToDeviceOrientation()
}
}

Related

Screen goes black after rotating the device only in ios 16

Some pages in the app support landscape mode.
After the ios 16 version was released
When turning the device horizontally, the screen becomes black, and only after turning horizontally again to the other side does the screen return to itself and the buttons function.
It is important to note that when I run on a device with iOS version 16 everything works great
I tried everything and could not find a solution
Has anyone tried this?
In my viewController:
var orientationType : UIInterfaceOrientationMask
{
guard let parent = self.parent else { return .allButUpsideDown }
guard parent is BaseChannelViewController else { return .allButUpsideDown }
return .portrait
}
public func animate(fullscreenPresentation completionBlock : AnimationCompletion?)
{
guard displayMode != .fullscreen else { completionBlock?(); return }
guard !isDisplayedModaly else { completionBlock?(); return }
switch transitionType
{
case .default : fallthrough
case .minimizable: fallthrough
case .interactive:
guard let transition = customTransitioningDelegate as? GAVideoPlayerZoomTransition else { break }
guard let presentingVC = dataSource?.presentingViewController(for: self) else { break }
let originFrame = dataSource?.initialFrameForTransitionToFullScreenDisplay(from: displayMode.initialScreenMode, for: self) ?? self.view.frame
transition.currentFrame = originFrame
NotificationCenter.default.post(name: .GAVideoPlayerViewControllerWillEnterFullscreen, object: self)
hideControlsNoAnimation()
if let _ = parent
{
removeFromParent()
}
// FIXME - Need this to prevent bad access crash, will show un balanced animation calls in the logger
view.removeFromSuperview()
let clientOrientationRawValue = clientOrientation.rawValue
presentingVC.present(self, animated: true) { [weak self] in
self?.displayMode = .fullscreen
let currentOrientationRawValue = UIDevice.current.orientation.rawValue
UIDevice.current.setValue(clientOrientationRawValue, forKey: "orientation")
UIDevice.current.setValue(currentOrientationRawValue, forKey: "orientation")
completionBlock?()
}
break
default: break
}
}
fileprivate var clientOrientation: UIDeviceOrientation
{
return UIDeviceOrientation(interfaceOrientationMask: clientSupportedInterfaceOrientations)
}
In AppDelegate:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask
{
guard let viewController = UIApplication.shared.topViewController() as? CustomOrientationViewController else { return .portrait }
return viewController.orientationType
}

Fix Orientation and list for changes - SWIFT

I'm new to iOS development and struggling with orientation checks. I have fixed the orientation for my view and now want to see the orientation it's held in.
How I've fixed it:
APP DELEGATE
return self.orientationLock
}
struct AppUtility {
static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.orientationLock = orientation
}
}
static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo
rotateOrientation:UIInterfaceOrientation) {
self.lockOrientation(orientation)
UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
}
}
VIEW CONTROLLER
override func viewWillAppear(_ animated: Bool) {
AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.portrait,
andRotateTo: UIInterfaceOrientation.portrait)
}
Now I want to listen for the orientation and print for the moment the changes.
VIEW CONTROLLER
override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
switch UIDevice.current.orientation {
case .portrait:
print("portrait")
case .faceUp:
print("faceUp")
case .landscapeLeft:
print("landscape left")
case .landscapeRight:
print("landscape right")
case .portraitUpsideDown:
print("upsidedown portrait")
default:
print("something else")
}
}
The trouble is the above code is waiting for the view to change, the view has been locked, so it'll never change.
How would you go about locking the view and then listening to see how the phone is held?
Much Appreciated
Shawn, thanks for the advice. In the end, that's what I did. Here's my code
You'll also need to import CoreMotion
var motion = CMMotionManager()
var currentOrientation: String = "Portrait"
func oritentationUpdateStart() {
motion.accelerometerUpdateInterval = 1.0
motion.startAccelerometerUpdates(to: OperationQueue.current! ) { (data, error) in
if let accel = data {
if (accel.acceleration.x > 0.5){
self.currentOrientation = "Upsidedown Landscape"
}
else if (accel.acceleration.y > 0.5) {
self.currentOrientation = "Upsidedown Portrait"
}
else if (accel.acceleration.x < -0.5) {
self.currentOrientation = "Landscape"
}
else if (accel.acceleration.y < -0.5) {
self.currentOrientation = "Portrait"
}
}
}
}

Rotate totally Landscape view when movie play in VLCPlayer with swift 3

I would like to rotate my view controller when movie play.
My question might be duplicate but I tried many ways when I find in stack overflow. But all codes do not work. May be I put the codes in wrong way.
override var shouldAutorotate: Bool {
return false
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
//return[.portrait,.landscapeRight]
return .landscapeLeft
}
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
//return UIInterfaceOrientation.landscapeRight
return .landscapeLeft
}
I put this code to vlcplayerviewcontroller.swift file.
When user clicks on play button, then it will goes to vlcplayerviewcontroller.swift and I would like to show the movie in Landscape mode automatically. I have no idea of how can I do this.
My reference link is How to lock orientation of one view controller to portrait mode only in Swift.
Allow only Portrait Device Orientation under project setting.
Add these lines into your AppDelegate file
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController) {
if (rootViewController.isKind(of: your_class_name_for_rotate.self)) {
// Unlock landscape view orientations for this view controller
return .allButUpsideDown;
}
}
// Only allow portrait (standard behaviour)
return .portrait;
}
private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController? {
if (rootViewController == nil) { return nil }
if (rootViewController.isKind(of: UITabBarController.self)) {
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
} else if (rootViewController.isKind(of: UINavigationController.self)) {
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
} else if (rootViewController.presentedViewController != nil) {
return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
}
return rootViewController
}
Add this line in viewDidLoad method of your view_controller_for_rotate
let value = UIInterfaceOrientation.landscapeLeft.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
And add these methods in same class
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
UIDevice.current.setValue(Int(UIInterfaceOrientation.portrait.rawValue), forKey: "orientation")
}
private func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.landscapeLeft
}
private func shouldAutorotate() -> Bool {
return true
}
I hope this helps.
I had a solution in the linked answer, but I adjusted for landscape. Follow these steps and it will give you the desired functionality.
Swift 3
In AppDelegate:
/// set orientations you want to be allowed in this property by default
var orientationLock = UIInterfaceOrientationMask.all
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return self.orientationLock
}
In some other global struct or helper class, here I created AppUtility:
struct AppUtility {
static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
if let delegate = UIApplication.shared.delegate as? AppDelegate {
delegate.orientationLock = orientation
}
}
/// Added method to adjust lock and rotate to the desired orientation
static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {
self.lockOrientation(orientation)
UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
}
}
Then in the desired ViewController you want to lock and rotate orientations, like your movie controller:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// rotate and lock
AppUtility.lockOrientation(.landscape, andRotateTo: .landscapeRight)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Don't forget to reset when view is being removed
AppUtility.lockOrientation(.all)
}

I want one Viewcontroller to be shown in landscape mode only

I'm currently working on an mobile Application which should be locked into Portrait mode only. As I can do this in my project settings it is not a problem, but I want one Viewcontroller to be shown in Landscape mode only.
I tried to disable to Portrait mode in the project settings and added this piece of code to my landscape view controller (and also the one which calls it, but with a portrait orientation):
let value = UIInterfaceOrientation.landscapeLeft.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
UIViewController.attemptRotationToDeviceOrientation()
The problem I face right now is, that this solution is not optimal. The user is still able to rotate his the device. How can I fix this?
Try to lock the auto rotate
override var shouldAutorotate : Bool {
// Lock autorotate
return false
}
This worked before iOS10
viewdidload:
UIDevice.current.setValue(UIInterfaceOrientation.landscapeRight.rawValue, forKey: "orientation")
Also have this in the viewcontroller:
override var shouldAutorotate : Bool {
return true
}
override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
return UIInterfaceOrientationMask.landscapeRight
}
override var preferredInterfaceOrientationForPresentation : UIInterfaceOrientation {
return UIInterfaceOrientation.landscapeRight
}
Below code will work fine.
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController) {
if (rootViewController.responds(to: Selector(("canRotate")))){
// Unlock landscape view orientations for this view controller
return .allButUpsideDown
}
}
// Only allow portrait (standard behaviour)
return .portrait
}
private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController? {
if (rootViewController == nil) { return nil }
if (rootViewController.isKind(of: UITabBarController.self)) {
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
} else if (rootViewController.isKind(of: UINavigationController.self)) {
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
} else if (rootViewController.presentedViewController != nil) {
return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
}
return rootViewController}} .
//Add the below method in ViewController .
#objc func canRotate() -> Void {}

Force landscape mode in one ViewController using Swift

I am trying to force only one view in my application on landscape mode,
I am calling:
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
}
The view is launched in the portrait mode, and keep rotating when I change the device orientation. The shouldAutorotate() method is never called.
Any help would be appreciated.
It may be useful for others, I found a way to force the view to launch in landscape mode:
Put this in the viewDidLoad():
let value = UIInterfaceOrientation.landscapeLeft.rawValue
UIDevice.current.setValue(value, forKey: "orientation")
and,
override var shouldAutorotate: Bool {
return true
}
Swift 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
}
If your view is embedded in a navigation controller, the above alone won't work. You have to cascade up by the following extension after the class definition.
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
}
}}
Swift 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
}
Swift 4 , Tested in iOS 11
You can specify the orientation in projectTarget -> General -> DeploymentInfo(Device Orientation) -> Portrait (Landscapeleft and Landscaperight are optional)
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
Thats it. :)
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.
In AppDelegate add this:
//Orientation Variables
var myOrientation: UIInterfaceOrientationMask = .portrait
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return myOrientation
}
Add this in viewController, that want to change orientation:
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)
}
For me, the best results came from combining Zeesha's answer and sazz's answer.
Add the following lines to AppDelegate.swift:
var orientationLock = UIInterfaceOrientationMask.portrait
var myOrientation: UIInterfaceOrientationMask = .portrait
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
return myOrientation
}
Add the following line to your view controller class:
let appDel = UIApplication.shared.delegate as! AppDelegate
Add the following lines to your view controller's viewDidLoad():
appDel.myOrientation = .landscape
UIDevice.current.setValue(UIInterfaceOrientation.landscapeLeft.rawValue, forKey: "orientation")
(optional) Add this line to your dismiss function:
appDel.myOrientation = .portrait
UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
What these lines of code do is set the default orientation to portrait, rotate it landscape when the view controller loads, and then finally reset it back to portrait once the view controller closes.
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
I needed to force one controller into portrait orientation. Adding this worked for me.
swift 4 with iOS 11
override var supportedInterfaceOrientations : UIInterfaceOrientationMask{
return .portrait
}
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
}
Works in 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;
}
}
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
}
*/
...
}
Swift 4
Trying to keep the orientation nothing worked but this for me:
...
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")
}
....
In ViewController in viewDidLoad Method call below function
func rotateDevice(){
UIDevice.current.setValue(UIInterfaceOrientation.landscapeLeft.rawValue, forKey: "orientation")
UIView.setAnimationsEnabled(true) // while rotating device it will perform the rotation animation
}`
App Delegate File Add Below Function & Variables
//Orientation Variables
var orientationLock = UIInterfaceOrientationMask.portrait
var myOrientation: UIInterfaceOrientationMask = .portrait
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { return .landscape }
According to the documentation of supportedInterfaceOrientations the shouldAutorotate method should return true or YES in Objective-C so that the supportedInterfaceOrientations are considered.
iOS 16+: requestGeometryUpdate(_:errorHandler:) API
As noted by #simonbs on Twitter, iOS 16 introduces a new API to update the current interface orientation. While in most cases, other, conventional methods will do the job, in some edge cases, they don't work (forcing the use of private APIs like suggested in this answer). Here, the new public API comes to the rescue.
The API works as follows:
windowScene.requestGeometryUpdate(.iOS(interfaceOrientations: .portrait))
You can optionally also pass a closure to handle errors (though I have no experience under which circumstances errors may occur):
windowScene.requestGeometryUpdate(.iOS(interfaceOrientations: .portrait)) { error in
// Handle error...
}
My solution is
just added below codes in 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)
}
}
And call below codes to change
override func viewDidLoad() {
super.viewDidLoad()
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
appDelegate.switchOrientation(to: .landscape)
}
}
or like below
#IBAction func actBack() {
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
appDelegate.switchOrientation(to: .portrait)
}
self.navigationController?.popViewController(animated: true)
}
// 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
}
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
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
}
}
class CustomUIViewController : UIViewController{
override var supportedInterfaceOrientations : UIInterfaceOrientationMask{
return .landscapeLeft
}
}
class ViewController: CustomUIViewController {
.
.
.
}

Resources