1

I'm trying to lock the rotation of my application using a bunch of methods that apple have now deprecated over the years and I'm at a loss.

There isn't a SceneDelegate or AppDelegate in Xcode projects anymore using SwiftUI meaning that I can't use any of the previous methods people came up with and programming the solution in SwiftUI: How do I lock a particular View in Portrait mode whilst allowing others to change orientation?. When I try to implement this solution into my program, Xcode returns a warning BUG IN CLIENT OF UIKIT: Setting UIDevice.orientation is not supported. Please use UIWindowScene.requestGeometryUpdate(_:)

Here is my current code

app.swift

import SwiftUI

@main
struct testApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    
    var body: some Scene {
        WindowGroup {
            //Main code here
        }
                
    }
    
}

mainView.swift

import SwiftUI

struct ContentView: View {
    
    var body: some View {
        ZStack {
            // rest of code is here
        }
    }.onAppear {
        UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation") // Forcing the rotation to portrait
        AppDelegate.orientationLock = .portrait // And making sure it stays that way
            
    }
        
}

class AppDelegate: NSObject, UIApplicationDelegate {
        
    static var orientationLock = UIInterfaceOrientationMask.all

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

1 Answer 1

2

As the warning message suggested, you can have a view request a particular orientation by digging out the UIWindowScene and requesting a geometry update (requires iOS 16).

For example, this can be done in .onAppear:

.onAppear {
    if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
        scene.requestGeometryUpdate(.iOS(interfaceOrientations: .portrait)) { error in
            // Handle denial of request.
        }
    }
}

The orientation will stay that way, even when leaving the view. So to have it go back to the current physical orientation, you can add an .onDisappear callback too:

.onDisappear {
    if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
        scene.requestGeometryUpdate(.iOS(interfaceOrientations: .all))
    }
}

An orientation request does not work like the device orientation lock does. If the user switches the physical device orientation after the view has appeared, the orientation change takes effect.

To override this, .onGeometryChange can be used to detect a change to the screen size. Another orientation request (to change it back again) can then be performed when it happens. The modifier .onGeometryChange triggers on first show too, so the .onAppear is no longer needed:

private func requestOrientations(_ orientations: UIInterfaceOrientationMask) {
    if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
        scene.requestGeometryUpdate(.iOS(interfaceOrientations: orientations)) { error in
            // Handle denial of request.
        }
    }
}

var body: some View {
    MyPortraitView()
        .onGeometryChange(for: CGSize.self, of: \.size) { _ in
            requestOrientations(.portrait)
        }
        .onDisappear {
            requestOrientations(.all)
        }
}

Note that changes to the view orientation are animated, both when the device orientation is first changed and then when the app reverts it back. So the user experience is not great.

For tech-savvy users, another way to lock the device orientation when an app is running is to create a shortcut on the device. The idea is to lock the device orientation when the app is launched and then unlock it when leaving the app. This gives a much better user experience. Google can help with the steps.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.