iOS Orientations: Landscape orientation for only one View Controller

Updated for iOS 9.3 in June 2016.

In an iOS app, there can often be situations, when it’s necessary to support landscape orientation for only one view controller. All other views should be in portrait. A movie player or a gallery are nice examples.

The simplest way that comes to mind is to mark Landscape Right and Left in Xcode project settings. But wait, all views are now rotating!

Screen Shot 2014-08-26 at 11.25.39

 

Okey, let’s mark shouldAutorotate NO in all other views.  Working? Yes. Nice solution? No.

Starting with iOS 6 there is a much more elegant solution actually – by using the UIApplicationDelegate’s method:

The demo app

The demo app has two view controllers.

The first view controller has only one button that presents the second view controller on press. It should support only Portrait orientation.

iOS Simulator Screen Shot 26 Aug 2014 12.51.45

 

iOS Simulator Screen Shot 26 Aug 2014 12.51.53

 

The second view controller has an ImageView and a dismiss button. It should also support Landscape orientation.

iOS Simulator Screen Shot 26 Aug 2014 12.53.59

 

Complete code

You can find the complete code here (tested with Xcode 7.3.1, iOS 9.3):

Handling iOS Orientations

In Xcode project settings only Portrait orientation should be marked:

Screen Shot 2014-08-26 at 11.25.39

All the magic happens in the AppDelegate:

Objective-C:

Swift:

It checks whether the window’s rootViewController has a presented controller and if yes, its class is checked. If the check is successful, UIInterfaceOrientationMaskAll is returned, otherwise only Portrait is supported.

A small problem with modal controllers

Everything seems to work, however there’s a small problem with modal controllers. If the modal controller was in landscape orientation before dismissal, the presenting controller won’t switch to the portrait after dismissal. That’s because the supportedInterfaceOrientationsForWindow method is called before the controller is actually dismissed and the presentedController check still returns All mask.

The small workaround is to check whether dismissal has been started.

In order to do it, a new property will be added to the SecondViewController: isPresented. It will be set to true during the initialisation and we’ll change its value once more before dismissing the SecondViewController.

Objective-C:

Swift:

The method in AppDelegate should also be slightly modified:

Objective-C:

Swift:

And now it’s all working as expected!

QEKDGs9v4P

Complete code

You can find the complete code here (tested with Xcode 7.3.1, iOS 9.3):

32 Comments
  1. David Lam
    • Farzana
  2. Henry Hins
  3. XYZ
    • Chris Jungmann
  4. XYZ
    • iOSDev Answer
      • SK
    • SK
  5. Shobhit
  6. Shobhit
    • SK
      • Chris Jungmann
  7. Alessandro
  8. Jon
  9. Jose
  10. fabb
  11. Pablo
  12. Guillermo
  13. Scatabrain
  14. Peterrr
    • Peterrr
  15. Ali Lopez
  16. MJ
  17. santhosh
  18. Ash
  19. XRumerTest
  20. ritaPef
  21. RuslanEffek
  22. ritaPef
  23. Natashagaw
  24. olgaCrort

Leave a Reply

Your email address will not be published. Required fields are marked *

*