Autorotation bug in iOS 13
Asked Answered
S

3

16

iOS 13/13.1 autorotation seems to be behave differently than iOS 12. For instance, my app allows user to lock interface orientation to portrait or landscape mode in settings.

  1. If I have portrait rotation lock on device and return .landscape in supportedInterfaceOrientations, the interface remains in portrait mode until I disable portrait lock orientation on device. This does not seem to be the case with iOS 12. Infact, supportedInterfaceOrientations is not even called in iOS 13!

  2. UIViewController.attemptRotationToDeviceOrientation() also does not work in such cases.

The root of the problem is I temporarily return shouldAutorotate to false while the app is initializing and when everything is initialized, I call UIViewController.attemptRotationToDeviceOrientation() to trigger autorotation. It triggers autorotation in iOS 12 but in iOS 13.1 it doesn't works.

Looks like a bug in iOS 13.1 probably. What do I do to force trigger autorotation?

EDIT: Looks like iOS 12.4.1 also ignores UIViewController.attemptRotationToDeviceOrientation(). There is something broken in autorotation in iOS 12.4.1 & above.

To be clear, this is what I want:

a. Even if portrait lock is set on iPhone, I wish my interface to autorotate to landscape mode if required,

b. UIViewController.attemptRotationToDeviceOrientation() alternative that triggers autorotation in all circumstances.

Shirring answered 16/9, 2019 at 6:54 Comment(1)
supportedInterfaceOrientations will not be called if viewcontroller is presented. It will be called when presented fullscreen, but by default, the UIModalpresentationStyle from iOS 13 is not fullscreen.Cranmer
G
3

From iOS 12.4.1, View Controller should be set to Full Screen to respect the auto-rotate orientation.

let vc = UIViewController()
vc.modalPresentationStyle = .fullScreen
self.present(vc, animated: true, completion: nil)
Godman answered 18/10, 2019 at 12:33 Comment(3)
Where does modal presentation comes into picture I wonder, the controller is not presented modally.Shirring
Well.. then set your navigation controller to full screen and return a different supported interface rotation when calling attempt device rotation on view did load.Godman
This solved it for me. I'm also calling present but because of the presented ViewController having a different preferredInterfaceOrientationForPresentation it is presented like it's a modal by default, maybe it's some iOS 13 behavior? In any case, thanks, this was very simple to add.Surname
O
0

Try this and see if this is something you are looking for:

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

    }

    @IBAction func btnLandscapeClicked(_ sender: Any) {
        let value = UIInterfaceOrientation.landscapeLeft.rawValue
        UIDevice.current.setValue(value, forKey: "orientation")
    }

    @IBAction func btnPortraitClicked(_ sender: Any) {
        let value = UIInterfaceOrientation.portrait.rawValue
        UIDevice.current.setValue(value, forKey: "orientation")
    }

}

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
        }
    }}
Obelia answered 27/9, 2019 at 6:36 Comment(3)
Well, isn't this a hack or undocumented API?Shirring
And I do not have any navigation controller in placeShirring
@DeepakSharma These are all available APIs by iOS SDK. I recommend you to put your ViewControllers in a NavigationController even if you are not using it, to get the same behaviour across your screens.Obelia
S
0

Replying for other people facing this issue, this is what worked for me. Go to the project settings General > Deployment Info and make sure you have checked "Requires full screen" setting.

Then paste the following code after the viewDidLoad block:

// Forbid autorotate
override open var shouldAutorotate: Bool {
   return false
}

// Specify the orientation
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return .landscape
}
Schutt answered 19/10, 2020 at 1:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.