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
}
}
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
}
}
}