2

In my App all Views are forced to portrait orientation via info.plist.

The exception should be "MyView" which should always be in landscape orientation.

What I did after taking a deeper look in SO:

Added in AppDelegate.swift:

static var orientationLock = UIInterfaceOrientationMask.portrait 

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

MyView.swift

struct MyView: View {
var body: some View {
    ZStack {
        // ...Some Images, etc.
    }
    .onAppear(perform: orientationLandscape)
    .onDisappear(perform: orientationPortrait)
}

func orientationLandscape() {
    AppDelegate.orientationLock = UIInterfaceOrientationMask.landscapeRight
    UIDevice.current.setValue(UIInterfaceOrientation.landscapeRight, forKey: "orientation")
    UINavigationController.attemptRotationToDeviceOrientation()
}

func orientationPortrait() {
    AppDelegate.orientationLock = UIInterfaceOrientationMask.portrait
    UIDevice.current.setValue(UIInterfaceOrientation.portrait, forKey: "orientation")
    UINavigationController.attemptRotationToDeviceOrientation()
}

}

UIDevice.current.setValue produces an error. Without that line I can change the orientation in MyView manually by holding the device in landscape/portrait but it should switch automatically when opening and closing the View.

Kuhlemann
  • 3,066
  • 3
  • 14
  • 41

3 Answers3

2

I solved this by orientating on bmjohns answer on a similar question:

  1. Add some code in AppDelegate (this part i had already)
  2. Make a struct and func which does the job (small adjustments for XCode 11 and SwiftUI were needed)
  3. Execute the func onAppear of your View
Kuhlemann
  • 3,066
  • 3
  • 14
  • 41
2

Since some info is missing on accepted answer i will put what i used in Swift 5

class AppDelegate: UIResponder, UIApplicationDelegate {


    var orientationLock = UIInterfaceOrientationMask.portrait

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

struct AppUtility {

    static func orientationLandscape() {
        if let delegate = UIApplication.shared.delegate as? AppDelegate {
                delegate.orientationLock = UIInterfaceOrientationMask.landscapeRight
        }
        UIDevice.current.setValue(UIInterfaceOrientation.landscapeRight.rawValue, forKey: "orientation")
        UINavigationController.attemptRotationToDeviceOrientation()
    }
    
    static func orientationPortrait() {
        if let delegate = UIApplication.shared.delegate as? AppDelegate {
                delegate.orientationLock = UIInterfaceOrientationMask.portrait
        }
        UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
        UINavigationController.attemptRotationToDeviceOrientation()
    }

}

.onAppear(perform: {
            AppUtility.orientationLandscape()
        }).onDisappear(perform: {
            AppUtility.orientationPortrait()
        })

Opening a view

.fullScreenCover(isPresented: $isPresented) {
                                NavigationLazyView(aView())
                            }
dqualias
  • 348
  • 1
  • 3
  • 12
1

there is a way for Force landscape orientation

Put the code in viewDidLoad()

let value = UIInterfaceOrientation.landscapeLeft.rawValue
UIDevice.current.setValue(value, forKey: "orientation")

and also,

override var shouldAutorotate: Bool {
    return true
}

for SwiftUI

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, forKey: "orientation")
UINavigationController.attemptRotationToDeviceOrientation()

And on dismissal,

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

Hope this will help you ...:)

Shivam Parmar
  • 1,520
  • 11
  • 27
  • First of all thank you for your answer. This sounds like a UIKit-Solution for me. Where do you put this code snippets in SwifUI? There is no viewDidLoad(). – Kuhlemann Mar 19 '20 at 14:13
  • 1
    In your edited answer there is not a single line different to my code which I have written in my question...this leads to the following error "Thread 1: signal SIGABRT" "orientationLock UIInterfaceOrientationMask [.landscapeLeft]" in AppDelegate when I open the view through my NavigationLink. – Kuhlemann Mar 22 '20 at 08:50