SwiftUI Force Portrait On All Except One View

I had to do something similar to this. Here's our approach.

We set the project orientation to only support Portrait mode.

Then in your AppDelegate add an instance variable for orientation and conform to the supportedInterfaceOrientationsFor delegate method.

static var orientationLock = UIInterfaceOrientationMask.portrait

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

Then when your about to present your landscape view perform the following actions:

AppDelegate.orientationLock = UIInterfaceOrientationMask.landscapeLeft
UIDevice.current.setValue(UIInterfaceOrientation.landscapeLeft.rawValue, forKey: "orientation")
UIViewController.attemptRotationToDeviceOrientation()

And on dismissal,

AppDelegate.orientationLock = UIInterfaceOrientationMask.portrait
UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
UIViewController.attemptRotationToDeviceOrientation()

Hope this helps!


A couple of tweaks to the answer above:

In AppDelegate as Jonathan's answer above:

static var orientationLock = 
UIInterfaceOrientationMask.portrait

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

Then in the 'destinationView' - the one that is landscape:

import SwiftUI

struct DestinationView: View {

var body: some View {
    Group {

        Text("Hello")

    }.onAppear {
        AppDelegate.orientationLock = UIInterfaceOrientationMask.landscapeLeft
        UIDevice.current.setValue(UIInterfaceOrientation.landscapeLeft.rawValue, forKey: "orientation")
        UINavigationController.attemptRotationToDeviceOrientation()
    }
    .onDisappear {
        DispatchQueue.main.async {
            AppDelegate.orientationLock = UIInterfaceOrientationMask.portrait
            UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
            UINavigationController.attemptRotationToDeviceOrientation()
        }
    }
}
}

Note the .rawValue in the UIDevice line which gets rid of the 'LongValue' error. Also, in the .onDisappear I had to use DispatchQueue.main.async in order to avoid an error when returning back to previous view which is in portrait.