Only ONE VIEW landscape mode
Asked Answered
R

5

47

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?

Reginaldreginauld answered 24/7, 2014 at 7:54 Comment(6)
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.Scever
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.Reginaldreginauld
Is all of the view (you want to limit orientation) inside UINavigationController?Scever
No, I didn't use UINavigationController. I used buttons and modals to move from one view to another.Reginaldreginauld
Try use all of the three methods: -(BOOL)shouldAutorotate -(NSUInteger)supportedInterfaceOrientations and - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation in the view controller you want to limit the orientation.Scever
this may helps https://mcmap.net/q/158150/-how-to-lock-orientation-of-one-view-controller-to-portrait-mode-only/6521116Soiree
A
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,

Anuradhapura answered 24/7, 2014 at 8:17 Comment(7)
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?Reginaldreginauld
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.Anuradhapura
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: developer.apple.com/library/ios/referencelibrary/GettingStarted/…Anuradhapura
thanks, I will create two UIViewController subclass and add the code you've provided. I really appreciate your helpReginaldreginauld
@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.Irreproachable
To mark shouldAutorotate NO in all other views is a tedious task. Answer given below should be the correct answer. https://mcmap.net/q/160851/-only-one-view-landscape-modeIrresolution
but, when I back to previous screen or push to other screen, It still hold Landscape mode?Cautery
C
93

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
Crepitate answered 24/7, 2014 at 8:18 Comment(15)
Can you tell me where is the code of the View Controllers that I've have added to my storyboard?Reginaldreginauld
If I got you right, this should help #11372708Crepitate
property 'shouldRotate' not found on object of class 'App Delegate*' - I paste it on my App Delegate .mReginaldreginauld
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.Crepitate
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!Eustasius
How do you go about getting it to return to portrait view when a different view is shown?Pelorus
@Pelorus you call [appDelegate setShouldRotate:NO];Crepitate
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.Pelorus
@Pelorus 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.Crepitate
How do I force it to update its orientation? Setting the BOOL shouldAutoRotate has no effect.Pelorus
@Pelorus (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 viewControllerTranspicuous
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask method is not called in iPad Pro, iPad AirAtlante
This is the most easiest way to do it right. thanks man!! cheersDamning
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate appDelegate.shouldRotate = true // or false to disable rotation For Swift 2.2Gallego
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.Goodygoody
A
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,

Anuradhapura answered 24/7, 2014 at 8:17 Comment(7)
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?Reginaldreginauld
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.Anuradhapura
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: developer.apple.com/library/ios/referencelibrary/GettingStarted/…Anuradhapura
thanks, I will create two UIViewController subclass and add the code you've provided. I really appreciate your helpReginaldreginauld
@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.Irreproachable
To mark shouldAutorotate NO in all other views is a tedious task. Answer given below should be the correct answer. https://mcmap.net/q/160851/-only-one-view-landscape-modeIrresolution
but, when I back to previous screen or push to other screen, It still hold Landscape mode?Cautery
T
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)
}
Tye answered 6/6, 2018 at 12:30 Comment(0)
L
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.

Lather answered 2/7, 2017 at 21:21 Comment(0)
L
1

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

Lanilaniard answered 19/4, 2016 at 12:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.