How to allow only one UIViewController to rotate in the direction of "Landscape" and "Portrait"?

My application is intended only for the iphone device (both for iphone 4 and 5), and for support only ios 6 .

My entire application only supports portrait mode. But there is one view called " ChatView " that I want to support in both landscape and portrait modes.

I set the required rotation of the device as follows:

enter image description here

I also tried the following code to support rotation in "ChatView" -

 -(BOOL)shouldAutorotate { return YES; } -(NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskLandscape; } 

But he could not turn this view.

I searched a lot for this, but could not find a solution to my problem.

And also in ChatView there are some objects, such as buttons, text fields, whose frames are set programmatically. So what I want to know is, should I also set frames for all of these objects for landscape mode?

Please help me.

Thank.....

+60
ios objective-c iphone uiviewcontroller
Jul 04 '13 at 8:57
source share
14 answers

I think that if you want to support only one rotation of the viewcontroller, this is not possible, since the application will follow the settings you set in the .plist file. An alternative that you can use is to support your application for both landscape and portrait, to slow down the rotation of all viewers to the portrait, except for viewing the chat.

EDIT

In a subclass of UINavigationController create a new file with the name, for example. CustomNavigationController and make it a subclass of UINavigationController .

.h file

 #import <UIKit/UIKit.h> @interface CustomNavigationController : UINavigationController @end 

.m file

 #import "CustomNavigationController.h" @interface CustomNavigationController () @end @implementation CustomNavigationController -(BOOL)shouldAutorotate { return NO; } -(UIInterfaceOrientationMask)supportedInterfaceOrientations { return UIInterfaceOrientationMaskAll; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return UIInterfaceOrientationIsPortrait(interfaceOrientation); } @end 

Set the class of your UINavigationController in your main xib class as CustomNavigationController . Hope this helps ypu ..

+28
Jul 04 '13 at 9:11
source share

Simple, but it works very well. IOS 7.1 and 8

AppDelegate.h

 @property () BOOL restrictRotation; 

AppDelegate.m

 -(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { if(self.restrictRotation) return UIInterfaceOrientationMaskPortrait; else return UIInterfaceOrientationMaskAll; } 

ViewController

 -(void) restrictRotation:(BOOL) restriction { AppDelegate* appDelegate = (AppDelegate*)[UIApplication sharedApplication].delegate; appDelegate.restrictRotation = restriction; } 

viewDidLoad

 [self restrictRotation:YES]; or NO 
+62
Sep 20 '14 at 19:35
source share

The controller of your view will never rotate to any position that is not supported by the application itself. You must turn on all possible rotations, and then in the presence of controllers that should not rotate, put the following lines

 - (UIInterfaceOrientationMask)supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait; } 

In ChatView, this should be:

 - (UIInterfaceOrientationMask)supportedInterfaceOrientations { return UIInterfaceOrientationMaskAll; } 

If you need to change the layout after the rotation, you must implement the corresponding changes in your subzones in

 - (void)viewWillLayoutSubviews 

Use self.view.bounds to check the current size of the view , since self.view.frame does not change after rotations.

+21
Jul 04 '13 at 9:15
source share

for the specific viewcontroller.m you want to rotate

add this method:

 - (BOOL)canAutoRotate { return YES; } 

then inside your AppDelegate.m

 - (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { UIViewController *currentViewController = [self topViewController]; if ([currentViewController respondsToSelector:@selector(canAutoRotate)]) { NSMethodSignature *signature = [currentViewController methodSignatureForSelector:@selector(canAutoRotate)]; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; [invocation setSelector:@selector(canAutoRotate)]; [invocation setTarget:currentViewController]; [invocation invoke]; BOOL canAutorotate = NO; [invocation getReturnValue:&canAutorotate]; if (canAutorotate) { return UIInterfaceOrientationMaskAll; } } return UIInterfaceOrientationMaskPortrait; } - (UIViewController *)topViewController { return [self topViewControllerWithRootViewController:[UIApplication sharedApplication].keyWindow.rootViewController]; } - (UIViewController *)topViewControllerWithRootViewController:(UIViewController *)rootViewController { if ([rootViewController isKindOfClass:[UITabBarController class]]) { UITabBarController* tabBarController = (UITabBarController*)rootViewController; return [self topViewControllerWithRootViewController:tabBarController.selectedViewController]; } else if ([rootViewController isKindOfClass:[UINavigationController class]]) { UINavigationController* navigationController = (UINavigationController*)rootViewController; return [self topViewControllerWithRootViewController:navigationController.visibleViewController]; } else if (rootViewController.presentedViewController) { UIViewController* presentedViewController = rootViewController.presentedViewController; return [self topViewControllerWithRootViewController:presentedViewController]; } else { return rootViewController; } } 
+15
Aug 26 '14 at 14:11
source share

The ted answer works well with the question mentioned by Alexander from Norway. But I thought that the question is not happening as Alexander explained,

When the ViewController B that is currently in the landscape (All orientations are included) returns back to ViewController A. (Portrait only) after the user clicks the back button, supportInterfaceOrientationsForWindow is not called and ViewController A ends in the landscape

In fact, when the ViewController B, which is currently in the landscape (all orientations included), returns back to ViewController A (portrait only) after the user clicks the back button, Appdelegate

 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; 

called out. But still, the root view controller is ViewController B (this rotation-enabled controller is turned on), ViewController A does not return to portrait orientation, since ViewController B still returns

 -(BOOL)shouldAutorotate{ return YES; } 

So, when you press the back button, “shouldAutorotate → NO” in ViewController B. Then, ViewController A will go into portrait orientation. This is what I did

 @property (nonatomic, assign) BOOL canAutoRotate; #pragma mark - Public methods - (BOOL)canAutoRotate { return _canAutoRotate; } #pragma mark - Button actions - (void)backButtonPressed:(UIButton *)sender { _canAutoRotate = NO; (...) } #pragma mark - Init - (id)init{ if(self=[super init]) { _canAutoRotate = YES; } return self; } 
+3
Feb 25 '15 at 9:54
source share

Swift 3 kosher version

I left this here only in case anyone has a problem.

Apple's documentation for supportedInterfaceOrientations states:

When the user changes the orientation of the device, the system calls this method on the root view controller or the topmost view controller presented, which fills the window. If the view controller supports the new orientation, the window and the view controller rotate to the new orientation. This method is only called if the viewAutorotate method of the view controller returns true.

In a few words, you should override supportedInterfaceOrientations in the root view controller so that it returns a value for its top child view controller and default value otherwise.

What you have to do is check if the application supports all modes (go to the Deployment Information section in the general goals settings or Info.plist), find out the class of your root view controller. It can be a universal UIViewController, UINavigationController, UITabBarController or some custom class. You can check it as follows:

 dump(UIApplication.shared.keyWindow?.rootViewController) 

Or in any other way that you like.

Let it be some kind of CustomNavigationController . Therefore, you should override supportedInterfaceOrientations as follows:

 class CustomNavigationController: UINavigationController { override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return topViewController?.supportedInterfaceOrientations ?? .allButUpsideDown } } 

In any view controller that should only support portrait orientation, for example, override supportedInterfaceOrientations as follows:

 class ChildViewController: UIViewController { override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .portrait } } 

Then be sure to check if the shouldAutorotate controller shouldAutorotate and the topmost presented view controller should already return true . If not, add this to the class definitions:

 override var shouldAutorotate: Bool { return true } 

Otherwise, supportedInterfaceOrientations will not be called at all.

Here you go!

If you need to fix the opposite problem, when only one view controller needs to support several orientations, and the others do not, make these changes to each view controller, except for this.

Hope this helps.

+2
Feb 23 '17 at 20:14
source share

Based on @iAnum's answer, I included the definition of autorotation and the definition of the UIViewController class.

This is due to the fact that otherwise the transition to the “special viewing controller” and from it will not be corrected in portrait orientation, and you will be stuck in an unsupported orientation.

I had only one kind of landscape support, so I just encoded it in a custom navigation view controller:

 -(BOOL)shouldAutorotate { return YES; } -(NSUInteger)supportedInterfaceOrientations { //Access the current top object. UIViewController *viewController = [self.viewControllers lastObject]; //Is it one of the landscape supported ones? if ([viewController isMemberOfClass:[SpecialViewController class]]) { return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight; } else return UIInterfaceOrientationMaskPortrait; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { //Access the current top object. UIViewController *viewController = [self.viewControllers lastObject]; //Is it one of the landscape supported ones? if ([viewController isMemberOfClass:[SpecialViewController class]]) { return interfaceOrientation; } else return UIInterfaceOrientationIsPortrait(interfaceOrientation); } 

The VC-related issues discussed here are discussed here https://stackoverflow.com/questions/67650/... where flipping back while in the landscape won't even call orientation methods, so you have to crack it a bit by showing and rejecting the modal view .

And then just remember that if you want willShowViewController to start, you need to set self.delegate = self and add UINavigationControllerDelegate to your custom navigation controller along with the code below.

 - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { return UIInterfaceOrientationPortrait; } - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { UIApplication* application = [UIApplication sharedApplication]; if (application.statusBarOrientation != UIInterfaceOrientationPortrait) { UIViewController *c = [[UIViewController alloc]init]; [c.view setBackgroundColor:[UIColor clearColor]]; [navigationController presentViewController:c animated:NO completion:^{ [self dismissViewControllerAnimated:YES completion:^{ }]; }]; } } 
+1
Jun 18 '14 at 12:05
source share

subclass UINavigationController as follows:

MyNavigationController.h

 #import <UIKit/UIKit.h> @interface MyNavigationController : UINavigationController @end 

MyNavigationController.m

 #import "MyNavigationController.h" #import "ServicesVC.h" @implementation MyNavigationController -(BOOL)shouldAutorotate{ return YES; } -(NSUInteger)supportedInterfaceOrientations{ if ([[self.viewControllers lastObject] isKindOfClass:[ServicesVC class]]) { return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight; } return UIInterfaceOrientationMaskAll; } @end 

Assuming your view manager is named: ServicesVC

+1
Nov 26 '14 at 19:42
source share

Here is Alexander's answer ( https://stackoverflow.com/posts/25507963/revisions ) in Swift:

 func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> Int { var currentViewController: UIViewController? = self.topViewController() if currentViewController != nil && currentViewController!.canAutoRotate() { return Int(UIInterfaceOrientationMask.All.rawValue) } return Int(UIInterfaceOrientationMask.Portrait.rawValue) } func topViewController() -> UIViewController? { if UIApplication.sharedApplication().keyWindow != nil { return self.topViewControllerWithRootViewController(UIApplication.sharedApplication().keyWindow!.rootViewController!) } return nil } func topViewControllerWithRootViewController(rootViewController: UIViewController?) -> UIViewController? { if rootViewController == nil { return nil } if rootViewController!.isKindOfClass(UITabBarController) { var tabBarController: UITabBarController = (rootViewController as? UITabBarController)! return self.topViewControllerWithRootViewController(tabBarController.selectedViewController) } else { if rootViewController!.isKindOfClass(UINavigationController) { var navigationController: UINavigationController = (rootViewController as? UINavigationController)! return self.topViewControllerWithRootViewController(navigationController.visibleViewController) } else { if (rootViewController!.presentedViewController != nil) { var presentedViewController: UIViewController = rootViewController!.presentedViewController! return self.topViewControllerWithRootViewController(presentedViewController) } else { return rootViewController } } } } 

In addition, you will need to add the following snippet to AppDelegate.swift:

 extension UIViewController { func canAutoRotate() -> Bool { return false }} 

And for the ViewControllers for which you want to allow all rotations, add this function:

 override func canAutoRotate() -> Bool { return true } 
+1
Aug 15 '15 at 4:23
source share

I am not sure about the history of this problem (now = iOS 10 timeframes), but there was a simple solution since I published this in October 2016.

Assuming you want to:

  • Support for iOS 7 and only new (including iOS 10)
  • Some view controllers must support all orientations, others must support a subset of orientations. An example of what I mean: one view controller should support only portrait, while all others should support all orientations
  • All view controllers should automatically rotate if they support rotation (this means that you do not want this code to fix this problem in view controllers).
  • Support for adding UINavigationController to XIBs / NIBs / Storyboards without having to do anything with them

... then (IMO) the easiest solution is to make UINavigationControllerDelegate NOT a subclass of UINavigationController (which violates Assumption 4 above).

When I decided this, I decided to make my first ViewController a UINavigationControllerDelegate . This view controller sets itself up as a delegate to the navigation controller and returns which orientations are allowed. In my case, the default value is that all orientations are allowed with the preferred portrait, but in one particular case only the portrait is allowed. The code below is from Swift 3 / Xcode 8:

  class iPhoneStartViewController: UIViewController { var navInterfaceOrientationMask: UIInterfaceOrientationMask? var navInterfaceOrientationPreferred: UIInterfaceOrientation! = .portrait override func viewDidLoad() { super.viewDidLoad() self.navigationController?.delegate = self } @IBAction func cameraButtonPressed(_ sender: AnyObject) { if PermissionsHelper.singleton().photosPermissionGranted() == false { self.navInterfaceOrientationMask = nil // default is: all orientations supported self.performSegue(withIdentifier: "segueToPhotoAccess", sender: self) } else { self.navInterfaceOrientationMask = .portrait // this stops the next view controller from being to rotate away from portrait self.performSegue(withIdentifier: "segueToCamera", sender: self) } } } // lock orientation to portrait in certain cases only. Default is: all orientations supported extension iPhoneStartViewController : UINavigationControllerDelegate { public func navigationControllerSupportedInterfaceOrientations(_ navigationController: UINavigationController) -> UIInterfaceOrientationMask { if let mask = self.navInterfaceOrientationMask { return mask } else { return .all } } public func navigationControllerPreferredInterfaceOrientationForPresentation(_ navigationController: UINavigationController) -> UIInterfaceOrientation { return self.navInterfaceOrientationPreferred } } 
+1
04 Oct '16 at 17:38
source share

I had the same situation. So I subclassed the UINavigationController into a CustomNavigationController, and inside this CustomNavigationController I wrote

 #define IOS_OLDER_THAN_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] < 6.0 ) #define IOS_NEWER_OR_EQUAL_TO_6 ( [ [ [ UIDevice currentDevice ] systemVersion ] floatValue ] >= 6.0 ) #pragma mark - Rotation #ifdef IOS_OLDER_THAN_6 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{ return (toInterfaceOrientation == UIInterfaceOrientationPortrait); } #endif #ifdef IOS_NEWER_OR_EQUAL_TO_6 -(BOOL)shouldAutorotate { return YES; } - (NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait;; } #endif 

I used this CustomNavigationController instead of the existing NavigationController.

Then inside the view controller, which you should display in the LandScape orientation, say LandScapeView, I wrote

 #pragma mark - Rotation #ifdef IOS_OLDER_THAN_6 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{ return (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight | toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft); } #endif #ifdef IOS_NEWER_OR_EQUAL_TO_6 -(BOOL)shouldAutorotate { return YES; } - (NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskLandscapeLeft; } #endif 

Inside the CustomNavigationController, I introduced this view controller, rather than popping into the navigation stack. So, LandScapeView appeared in the LandScape orientation.

 LandScapeView *graph = [[LandScapeView alloc]init....]; [self presentViewController:graph animated:YES completion:nil]; 

I did not change anything in the Orientation of the supported interface in the project settings.

0
Jul 05 '13 at 4:11
source share

// paste this method into the deligate application class

 - (UIInterfaceOrientationMask)application:(UIApplication )application supportedInterfaceOrientationsForWindow:(UIWindow )window { if ([self.window.rootViewController.presentedViewController isKindOfClass: [_moviePlayerController class]]) { if (self.window.rootViewController.presentedViewController) return UIInterfaceOrientationMaskAll; else return UIInterfaceOrientationMaskPortrait; } else return UIInterfaceOrientationMaskPortrait; } 
0
Feb 02 '16 at 15:43
source share

If the application supports from iOS7 to iOS9 , use this code for orientation:

 #if __IPHONE_OS_VERSION_MAX_ALLOWED < 90000 - (NSUInteger)supportedInterfaceOrientations #else - (UIInterfaceOrientationMask)supportedInterfaceOrientations #endif { if([AppDelegate isPad]) return UIInterfaceOrientationMaskAll; else return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown; } 
0
Aug 09 '16 at 6:07
source share

I know this question is very old, but it needs an updated answer. The easiest and most correct way to achieve this result is to enable Portrait and Landscape in the settings of your application. Then add this code to your application delegate:

  func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask { if let navigationController = self.window?.rootViewController as? UINavigationController { if navigationController.visibleViewController is INSERTYOURVIEWCONTROLLERHERE { return UIInterfaceOrientationMask.All } else { return UIInterfaceOrientationMask.Portrait } } return UIInterfaceOrientationMask.Portrait } 

Remember to replace "INSERTYOURVIEWCONTROLLERHERE" with your view controller.

0
Aug 24 '16 at 19:30
source share



All Articles