⚠️Device Orientation != Interface Orientation⚠️
Swift 5.* iOS16 and below
You should really make a difference between:
- Device Orientation => Indicates the orientation of the physical device
- Interface Orientation => Indicates the orientation of the interface displayed on the screen
There are many scenarios where those 2 values are mismatching such as:
- When you lock your screen orientation
- When you have your device flat
In most cases you would want to use the interface orientation and you can get it via the window:
private var windowInterfaceOrientation: UIInterfaceOrientation? {
return UIApplication.shared.windows.first?.windowScene?.interfaceOrientation
}
In case you also want to support < iOS 13 (such as iOS 12) you would do the following:
private var windowInterfaceOrientation: UIInterfaceOrientation? {
if #available(iOS 13.0, *) {
return UIApplication.shared.windows.first?.windowScene?.interfaceOrientation
} else {
return UIApplication.shared.statusBarOrientation
}
}
Now you need to define where to react to the window interface orientation change. There are multiple ways to do that but the optimal solution is to do it within
willTransition(to newCollection: UITraitCollection
.
This inherited UIViewController method which can be overridden will be trigger every time the interface orientation will be change. Consequently you can do all your modifications in the latter.
Here is a solution example:
class ViewController: UIViewController {
override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) {
super.willTransition(to: newCollection, with: coordinator)
coordinator.animate(alongsideTransition: { (context) in
guard let windowInterfaceOrientation = self.windowInterfaceOrientation else { return }
if windowInterfaceOrientation.isLandscape {
// activate landscape changes
} else {
// activate portrait changes
}
})
}
private var windowInterfaceOrientation: UIInterfaceOrientation? {
return UIApplication.shared.windows.first?.windowScene?.interfaceOrientation
}
}
By implementing this method you'll then be able to react to any change of orientation to your interface. But keep in mind that it won't be triggered at the opening of the app so you will also have to manually update your interface in viewWillAppear()
.
I've created a sample project which underlines the difference between device orientation and interface orientation. Additionally it will help you to understand the different behavior depending on which lifecycle step you decide to update your UI.
Feel free to clone and run the following repository:
https://github.com/wjosset/ReactToOrientation