iOS 16 Scene orientation issue

15.7k views Asked by At

I always received this error when I tried to allowed only portrait orientation on my controller: Error Domain=UISceneErrorDomain Code=101 "None of the requested orientations are supported by the view controller. Requested: landscapeLeft; Supported: portrait" UserInfo={NSLocalizedDescription=None of the requested orientations are supported by the view controller. Requested: landscapeLeft; Supported: portrait}

I called this method:

func updateOrientation(orientation: UIInterfaceOrientationMask) {
        if #available(iOS 16, *) {
            DispatchQueue.main.async {
                let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
                self.setNeedsUpdateOfSupportedInterfaceOrientations()
                self.navigationController?.setNeedsUpdateOfSupportedInterfaceOrientations()
                windowScene?.requestGeometryUpdate(.iOS(interfaceOrientations: orientation)) { error in
                    print(error)
                    print(windowScene?.effectiveGeometry )
                }
            }
        }
    }

Did someone face the same issue ?

5

There are 5 answers

2
OrrHsiao On

try it in Appdelegate

  • (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { return UIInterfaceOrientationMaskAll; }
0
Krishnarjun Banoth On

Yes, I faced the same issue and resolved it as below. Provided error clearly saying that we are trying to rotate the device where we are restricting it to use only in one mode previously somewhere in the app. In my case I was implemented below method in Appdelegate.swift

var myOrientation: UIInterfaceOrientationMask = .portrait

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

so restricting it to only use the portrait mode, caused to fail the rotation of the app in landscape mode.

By changing the orientation to all, makes it work.

var myOrientation: UIInterfaceOrientationMask = .portrait
1
Jeffrey On

J.Y.527 found a solution : https://stackoverflow.com/a/73735976/2858994

It looks like a workaround, but it's fixed the problem in my case.

the trick is to update the AppDelegate supported orientation when you need to rotate.

In Your AppDelegate :

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

Then in your controller :

 static func SwitchOrientation(orientation : UIInterfaceOrientationMask, viewController : UIViewController){
 
    
    
    if #available(iOS 16.0, *) {
        (UIApplication.shared.delegate as? AppDelegate)?.orientation = orientation
                            
        let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
        windowScene?.requestGeometryUpdate(.iOS(interfaceOrientations: orientation))

        UIApplication.navigationTopViewController()?.setNeedsUpdateOfSupportedInterfaceOrientations()
        
        DispatchQueue.main.async {
                    let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
                    viewController.setNeedsUpdateOfSupportedInterfaceOrientations()
                    viewController.navigationController?.setNeedsUpdateOfSupportedInterfaceOrientations()
                    windowScene?.requestGeometryUpdate(.iOS(interfaceOrientations: orientation)) { error in
                        print(error)
                        print(windowScene?.effectiveGeometry ?? "")
                    }
                }
    

    } else{
        UIDevice.current.setValue(orientation, forKey: "orientation")
    }
  
}
1
赵希帆 On

You can try like this, it work for me

- (void)forceOrientation:(UIDeviceOrientation)orientation {
    if (@available(iOS 16.0, *)) {
        UIInterfaceOrientationMask orientationMask = (1 << orientation);
        [self setNeedsUpdateOfSupportedInterfaceOrientations];
        UIWindowScene *windowScene = (UIWindowScene *) 
        [UIApplication sharedApplication].connectedScenes.allObjects.firstObject;
        for (UIWindow *windows in windowScene.windows) {
            [windows.rootViewController setNeedsUpdateOfSupportedInterfaceOrientations];
        }
        UIWindowSceneGeometryPreferencesIOS *geometryPreferences = [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:orientationMask];
        [windowScene requestGeometryUpdateWithPreferences:geometryPreferences errorHandler:nil];
    } else {
       [[UIDevice currentDevice] setValue:@(orientation) forKey:@"orientation"];
       [UIViewController attemptRotationToDeviceOrientation];
    }
}
3
Amrit Tiwari On

Here is the best and easy solution that works in all iOS version including iOS 16+.

Initially set the orientation value on AppDelegate as here I am forcing app to only one orientation

var orientationLock = UIInterfaceOrientationMask.portrait

and function as

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

then you can make an extension class of UIViewController as

 extension UIViewController {

    /// Lock your orientation
    func lockOrientation(_ orientation: UIInterfaceOrientationMask) {

        if let delegate = UIApplication.shared.delegate as? AppDelegate {
            delegate.orientationLock = orientation
        }

        if #available(iOS 16.0, *) {
            self.setNeedsUpdateOfSupportedInterfaceOrientations()
        }
    }

    /// OPTIONAL Added method to adjust lock and rotate to the desired orientation
    func lockOrientation(
        _ allowOrientation: UIInterfaceOrientationMask,
        andRotateTo rotateOrientation: UIInterfaceOrientationMask) {
            
        self.lockOrientation(allowOrientation)

        if #available(iOS 16.0, *) {
            UIViewController.attemptRotationToDeviceOrientation()
            let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
            windowScene?.requestGeometryUpdate(.iOS(interfaceOrientations: rotateOrientation))

            self.setNeedsUpdateOfSupportedInterfaceOrientations()

        } else {

            UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
            UINavigationController.attemptRotationToDeviceOrientation()
        }
    }
}

you can call the method from your controller to enable which orientation you want. Here, I put all orientation.

        self.lockOrientation(.all)

And If you want to forcefully change orientation of the view controller which locking orientation then call as from your ViewController

    self.lockOrientation(.all, andRotateTo: .portrait)

Here, I am locking my orientation to all and forcing to change to portrait.

Good luck!!!