Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI force device rotation programmatically

My app has certain orientations that are set depending on device. For iPads it is set to landscape and portrait for iPhones. This works fine except I want to allow one view to be shown in landscape for iPhone. I need the view to automatically rotate to landscape and rotate back to portrait after leaving that view. I have the following code that locks the orientation for that view but the device has to be manually rotated back and forth. Is there a way to auto-rotate the device?

.onAppear {
            if(deviceType == .phone){
                UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
                AppDelegate.orientationLock = .landscape

            }
        }
.onDisappear {
            if(deviceType == .phone){
                AppDelegate.orientationLock = .portrait
            }
        }
like image 688
Brian Kalski Avatar asked Sep 01 '26 17:09

Brian Kalski


1 Answers

enter image description here

This can be achieved using a View extension that will update the view's orientation. Let’s make our own extension which will rotate the view on given orientation, back and forth.

extension View {
    @ViewBuilder
    func forceRotation(orientation: UIInterfaceOrientationMask) -> some View {
        if UIDevice.current.userInterfaceIdiom == .phone {
            self.onAppear() {
                AppDelegate.orientationLock = orientation
            }
            // Reset orientation to previous setting
            let currentOrientation = AppDelegate.orientationLock
            self.onDisappear() {
                AppDelegate.orientationLock = currentOrientation
            }
        } else {
            self
        }
    }
}

In AppDelegate, add:

class AppDelegate: NSObject, UIApplicationDelegate {

    static var orientationLock = UIInterfaceOrientationMask.portrait {
        didSet {
            if #available(iOS 16.0, *) {
                UIApplication.shared.connectedScenes.forEach { scene in
                    if let windowScene = scene as? UIWindowScene {
                        windowScene.requestGeometryUpdate(.iOS(interfaceOrientations: orientationLock))
                    }
                }
                UIViewController.attemptRotationToDeviceOrientation()
            } else {
                if orientationLock == .landscape {
                    UIDevice.current.setValue(UIInterfaceOrientation.landscapeRight.rawValue, forKey: "orientation")
                } else {
                    UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
                }
            }
        }
    }
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        return true
    }
    
    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        return AppDelegate.orientationLock
    }
}

This little example demonstrate how you can use this extension:

struct ContentView: View {
        
    var body: some View {
        NavigationView {
            List(Orientation.allCases, id: \.self) { orientation in
                       NavigationLink(orientation.title) {
                           ZStack {
                               Text(orientation.title)
                           }
                           .forceRotation(orientation: orientation.mask)  // << Update the required orientation here.. 
                       }
                   }
               }
        }
}

enum Orientation: Int CaseIterable {
    case landscapeLeft
    case landscapeRight
    
    var title: String {
        switch self {
        case .landscapeLeft:
            return "LandscapeLeft"
        case .landscapeRight:
            return "LandscapeRight"
        }
    }
    
    var mask: UIInterfaceOrientationMask {
        switch self {
        case .landscapeLeft:
            return .landscapeLeft
        case .landscapeRight:
            return .landscapeRight
        }
    }
}
like image 170
Kush Bhavsar Avatar answered Sep 05 '26 08:09

Kush Bhavsar



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!