To change the supported orientations for a UIViewController, we can override the supportedInterfaceOrientations. However, it’s not always working as we expected in some situations.

shouldAutorotate

The system only calls this method if the view controller’s shouldAutorotate method returns true.

According to the documentation, override shouldAutorotate to false will cause supportedInterfaceOrientations not working. However, if we only plan to support only one orientation, it seems alright to override shouldAutorotate to false.

Container View Controller

When the user changes the device orientation, the system calls this method on the root view controller or the topmost presented view controller that fills the window.

When displaying a view controller in a container view controller, the view controller is not presented by the container view controller, but just embedded in the container view controller’s view.

So it’s not in accord with the quotation above from the documentation. Even when we are using UINavigationController, UITabBarControllers etc.

We have to override supportedInterfaceOrientations for the container view controller. Here is an example subclass of UINavigationController.

class NavigationController: UINavigationController {

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        topViewController?.supportedInterfaceOrientations ?? .all
    }
}

modalPresentationStyle

the topmost presented view controller that fills the window

The topmost presented view controller needs to fill the window to make supportedInterfaceOrientations to take effect.

So instead of using the default modalPresentationStyle from iOS 13-pageSheet, we have to use some styles that fill the window, such as fullScreen.

Undocumented Behaviors(?)

With three points should be enough for us to configure supportedInterfaceOrientations. But when we are using overFullScreen, there will be more unexpected behaviors that I couldn’t find related description from the documentation.

The first one is, when we present a portrait view controller from an all view controller by overFullScreen, the result will be the same as by fullScreen. However, when we present an all view controller from a portrait view controller by overFullScreen, the presented view controller can’t rotate.

I tried some pattern and found out that, supportedInterfaceOrientations only works when supportedInterfaceOrientations of the presented view controller is less than the presenting view controller.

The second one is more like a bug. If we present an all view controller by overFullScreen, and then present a portrait view controller by fullScreen, the third view controller will be able to rotate.

I have no idea why this will happen. And to avoid this behavior we have to override supportedInterfaceOrientations for the root view controller to find the proper child and use it’s supportedInterfaceOrientations.

Conclusion

Override supportedInterfaceOrientations can change the supported orientations for a UIViewController, but it has some requirement to fulfill and may have some strange behaviors in some situations. Instead of relying on the default behaviors of it, we may consider overriding supportedInterfaceOrientations of the root view controller to define the specific behaviors we want.