As of iOS 11.2 I notice that (BOOL)shouldAutorotate, (BOOL)shouldAutorotateToInterfaceOrientation, (UIInterfaceOrientationMask)supportedInterfaceOrientations
etc. are no longer called.
How do I prevent rotation to a certain orientation now?
I can switch off rotation on the Deployment level of the target, but what I actually want it to switch off rotation just for the iPhone X. I have an older app without storyboards, and don't want to change the app to honour the silly notch in the screen in landscape mode.
Landscape IS useful in my App, as on iPhone you get a wider keyboard in landscape mode, which is nice. Else I'll just remove rotation for all iPhone models..
It is in the documentation for UIViewController
:
"As of iOS 8, all rotation-related methods are deprecated. Instead, rotations are treated as a change in the size of the view controller’s view and are therefore reported using..."
and:
"You can override the preferredInterfaceOrientationForPresentation.."
but that is not called either. Not in the root view controller, nor in other viewcontrollers.
So, how do I prevent rotation to a certain orientation now, programmatically?
As mentioned in documentation
A view controller can override the supportedInterfaceOrientations method to limit the list of supported orientations.
So we need to override shouldAutorotate
and supportedInterfaceOrientation
to target view controllers
.
Typically, the system calls this method only on the root view controller of the window or a view controller presented to fill the entire screen.
This will work if you have very simple configuration like your target view controller
is the rootViewController
of window
or being presented covering whole screen.
But when you have other configuration like your target view controller
is embedded in some other container view controller like UINavigationController
or UITabBarController
, so now application's window will only ask its rootViewController
(now container view controller
) for supportedInterfaceOrientation
.
Now further reading the documentation,
child view controllers use the portion of the window provided for them by their parent view controller and no longer participate directly in decisions about what rotations are supported.
So may be default implementation of these container view controllers not asking there children for there supportedInterfaceOrientation
preference.
So to allow our target child view controller
to specify there supportedIntefaceOrientation
we need to tell there container view controller to do so.
In case of UINavigationController
extension UINavigationController {
open override var shouldAutorotate: Bool {
return true
}
open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return topViewController?.supportedInterfaceOrientations ?? .allButUpsideDown
}
}
And in case or UITabBarController
extension UITabBarController {
open override var shouldAutorotate: Bool {
return true
}
open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return selectedViewController?.supportedInterfaceOrientations ?? .allButUpsideDown
}
}
EDIT
To implement proper rotation behaviour in your view controllers, you should subclass these ContainerViewController
(UINavigationController
, UITabBarController
, UISplitViewController
etc) and then override these properties, because extending these UIKit
Classes globally will cause unexpected behavior as mentioned in Customizing Existing Classes.
If the name of a method declared in a category is the same as a method in the original class, or a method in another category on the same class (or even a superclass), the behavior is undefined as to which method implementation is used at runtime. This is less likely to be an issue if you’re using categories with your own classes, but can cause problems when using categories to add methods to standard Cocoa or Cocoa Touch classes.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With