44

I finished my iOS app but I need to set only ONE view to landscape mode, the rest of the views can only be seen in portrait mode.

I'm using Xcode 5.1 and I created all of my Views by dropping in my storyboard View Controllers from the right panel, so if you are going to tell me to write some code somewhere, please tell me exactly where I need to write it.

I read one solution here UINavigationController Force Rotate but I don't know where to write that code. Do I need to create one UIViewController manually?

Community
  • 1
  • 1
maeq
  • 1,073
  • 1
  • 12
  • 23
  • If you want to support just one orientation in every view controller select your project (top item on the left top corner in xCode) click on targets (your app name) go to General tab and in Device Orientation leave checked only the orientation you want your app to handle. – Greg Jul 24 '14 at 07:58
  • Maybe i didn't make my self clear. I have over 40 views that should only be seend in protrait mode, and I have one view that should only be seen in landscape mode. – maeq Jul 24 '14 at 08:00
  • Is all of the view (you want to limit orientation) inside UINavigationController? – Greg Jul 24 '14 at 08:03
  • No, I didn't use UINavigationController. I used buttons and modals to move from one view to another. – maeq Jul 24 '14 at 08:06
  • Try use all of the three methods: -(BOOL)shouldAutorotate -(NSUInteger)supportedInterfaceOrientations and - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation in the view controller you want to limit the orientation. – Greg Jul 24 '14 at 08:17
  • this may helps http://stackoverflow.com/q/28938660/6521116 – LF00 May 04 '17 at 06:01

5 Answers5

91

Swift

AppDelegate.swift

internal var shouldRotate = false
func application(_ application: UIApplication,
                 supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return shouldRotate ? .allButUpsideDown : .portrait
}

Your landscape view controller

let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.shouldRotate = true // or false to disable rotation

Objective-C

AppDelegate.h

@property (assign, nonatomic) BOOL shouldRotate;

AppDelegate.m

- (UIInterfaceOrientationMask)application:(UIApplication *)application
 supportedInterfaceOrientationsForWindow:(UIWindow *)window {
    return self.shouldRotate ? UIInterfaceOrientationMaskAllButUpsideDown
                             : UIInterfaceOrientationMaskPortrait;
}

Your landscape view controller

AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
[appDelegate setShouldRotate:YES]; // or NO to disable rotation
shabbirv
  • 8,958
  • 4
  • 33
  • 34
Yaroslav
  • 2,435
  • 1
  • 19
  • 36
  • Can you tell me where is the code of the View Controllers that I've have added to my storyboard? – maeq Jul 24 '14 at 08:36
  • If I got you right, this should help http://stackoverflow.com/questions/11372208/classes-for-new-view-controller-in-storyboard – Yaroslav Jul 24 '14 at 09:14
  • property 'shouldRotate' not found on object of class 'App Delegate*' - I paste it on my App Delegate .m – maeq Jul 24 '14 at 09:29
  • 2
    You didn't make it public in AppDelegate.h, did you? Paste this: @property (assign, nonatomic) BOOL shouldRotate; And sorry, but you should learn more of these simple things. I can suggest you go to iTunes U. There are lots of video courses teaching you step by step all the essential things about iOS 7 development. – Yaroslav Jul 24 '14 at 09:46
  • This is no doubt the best way to do it....just let AppDelegate control orientation changes unsing setShouldRotate:YES/NO in every ViewController......also no need to set anything on Info.plist or Deployment Info....great! – Marcos Reboucas May 28 '15 at 23:56
  • How do you go about getting it to return to portrait view when a different view is shown? – user717452 Aug 26 '15 at 15:07
  • @user717452 you call [appDelegate setShouldRotate:NO]; – Yaroslav Aug 26 '15 at 15:09
  • I have a table view that is the root called "Vimeo" I want it portrait, and "VimeoWebView" landscape. I have `[appDelegate setShouldRotate:YES];` in viewWillAppear of the latter, and it is set to NO in the former. The first will not rotate when it is on screen, and second will. However, if you rotate the second, then pop back to any other view, those views stay rotated. – user717452 Aug 26 '15 at 15:10
  • 1
    @user717452 It seems you need to force UIViewController to update its orientation. I'm not sure why it doesn't do it on its own. I haven't had this problem. – Yaroslav Aug 26 '15 at 15:17
  • How do I force it to update its orientation? Setting the BOOL shouldAutoRotate has no effect. – user717452 Aug 26 '15 at 15:20
  • @user717452 (Swift) put the code --> let value = UIInterfaceOrientation.LandscapeLeft.rawValue UIDevice.currentDevice().setValue(value, forKey: "orientation") let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate appDelegate.shouldRotate = true in your viewController – charles.cc.hsu Dec 23 '15 at 08:38
  • func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask method is not called in iPad Pro, iPad Air – Saty Feb 16 '16 at 05:07
  • This is the most easiest way to do it right. thanks man!! cheers – Bhaumik Desai Oct 29 '16 at 20:15
  • let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate appDelegate.shouldRotate = true // or false to disable rotation For Swift 2.2 – Statik Nov 10 '16 at 12:01
  • 1
    Terrible solution. Yes it will allow the view controller to rotate, but dismissing a landscaped view controller and making sure the app goes back in portrait mode first if cumbersome. Wouldn't recommend this approach. – zumzum Apr 06 '21 at 16:32
39

I am gonna suppose you are targeting iOS 7 here (using XCode 5.1, I think I am right).

First, you have to understand that in order to open even just one view out of over 40 in landscape, your app should allow both landscape and portrait interface orientations. It is the case by default, but you can check it in your target's settings, General tab, Deployment Info section (see screenshot below).

enter image description here

Then, because you allowed both landscape and portrait for the entire app, you will have to tell every portrait-only UIViewController that it should not autorotate, adding this method's implementation:

- (BOOL)shouldAutorotate {
  return NO;
}

Finally, for your specific landscape-only controller, and because you said you are presenting it modally, you can just implement these methods:

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
  return UIInterfaceOrientationLandscapeLeft; // or Right of course
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
  return UIInterfaceOrientationMaskLandscape;
}

Hope this will help,

Saqib Saud
  • 2,799
  • 2
  • 27
  • 41
Zedenem
  • 2,479
  • 21
  • 23
  • That is a well-explained answer, thank you. But I don't know where to write that code, can you tell me the file name please? – maeq Jul 24 '14 at 08:30
  • 2
    Hi, you should write the first code snippet in all your `XXXViewController.m` files for which you want the view to stay in portrait. The second goes in the `YYYViewController.m` file for which you want the view to stay in landscape. If you just dragged view controllers into your storyboard, you should connect your portrait view controllers to at least one `UIViewController` subclass (Create/New/File + subclass of UIViewController) and your landscape one to a different subclass of `UIViewController`. – Zedenem Jul 24 '14 at 08:42
  • If you are not able to understand my previous comment, I would strongly suggest that you take a basic iOS development tutorial, like this one: https://developer.apple.com/library/ios/referencelibrary/GettingStarted/RoadMapiOS/FirstTutorial.html – Zedenem Jul 24 '14 at 08:43
  • thanks, I will create two UIViewController subclass and add the code you've provided. I really appreciate your help – maeq Jul 24 '14 at 08:45
  • 1
    @RajuGujarati AFAIK, is still working even in ios 9.2. Check all the basics: (1) testing on device that does not have ORIENTATION LOCK on in user settings. That is, make sure other apps are successfully rotating. (2) first just add the setting that allows views to rotate. Create two views "A" and "B". Verify both views are rotating. (3) put the "autorotate NO" code in A's controller. Vew A stops rotating. View B does rotate. (4) put the two methods that mention landscape in View B's controller. "B" must NOT have the code mentioned in (3). "B" now stays landscape. "A" still stays portrait. – ToolmakerSteve Dec 19 '15 at 19:24
  • To mark shouldAutorotate NO in all other views is a tedious task. Answer given below should be the correct answer. http://stackoverflow.com/a/24928474/1556386 – Baig May 22 '16 at 05:33
  • but, when I back to previous screen or push to other screen, It still hold Landscape mode? – Tà Truhoada May 18 '17 at 07:25
11

SWIFT4

Add below code lines to your AppDelegate

var orientationLock = UIInterfaceOrientationMask.portrait
        
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
  return self.orientationLock
}
        
struct AppUtility {
  static func lockOrientation(_ orientation: UIInterfaceOrientationMask) {
    if let delegate = UIApplication.shared.delegate as? AppDelegate {
      delegate.orientationLock = orientation
    }
  }
            
  static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) {
    self.lockOrientation(orientation)
    UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation")
  }
}

Add below code to the Controller you want to landscape

override func viewDidLoad() {
  super.viewDidLoad()
}
        
override func viewWillAppear(_ animated: Bool) {
  AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.landscapeRight, andRotateTo: UIInterfaceOrientation.landscapeRight)
}
    
override func viewWillDisappear(_ animated : Bool) {
  super.viewWillDisappear(animated)
  AppDelegate.AppUtility.lockOrientation(UIInterfaceOrientationMask.portrait, andRotateTo: UIInterfaceOrientation.portrait)
}
aturan23
  • 4,798
  • 4
  • 28
  • 52
Bhavesh Patel
  • 596
  • 4
  • 17
6

To follow up on Yaroslav's solution, in order to allow rotation to landscape mode at only one view, the landscape view controller should have shouldRotate set to YES in its viewWillAppear method, and to NO in its viewWillDisappear.

If you only setShouldRotate to YES at the viewWillAppear, after existing this view controller, all other view controllers will be rotated as well. So, you have to setShouldRotate to NO in its viewWillDisappear to restrict the portrait view from being rotated.

fujianjin6471
  • 5,168
  • 1
  • 36
  • 32
Tim Le
  • 229
  • 3
  • 5
1

You should declare shouldRotate as internal to get rid of the public property in none public class warning. internal var shouldRotate = false

bleft
  • 47
  • 5