Locking Portrait Orientation in View? iOS 7 - ios

So, I want to lock the orientation of my home page to portrait, and the Home page ONLY.
I am using a tab bar controller, so the initial view is the tab controller, but the view controller that appears first is the first tab, e.g. the Home page.
I would like to make it so that when the user goes to rotate the device, it WILL NOT rotate to landscape on this page. However all other pages can rotate.
I have searched around, and nothing seems to be specific to iOS 7, and the one that is specific to iOS 7 doesn't work…
Please help, thank you!
The image below describes what I DON"T want to happen, for this page.

Implement the following in your implementation
- (NSUInteger) supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
This should give you the results you are looking for!

Use this code
#implementation UINavigationController (Rotation_IOS6)
-(BOOL)shouldAutorotate
{
return UIInterfaceOrientationMaskPortrait;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
#end

The problem is, as you've rightly pointed out, that your home tab is not the topmost view controller.
From my limited knowledge on the subject I can only think of the following:
Create another tab view controller and implement the methods to control orientation, i.e. shouldAutorotate and supportedInterfaceOrientations;
Make this controller the first one at startup;
Route the other tabs down to the original tab controller (the one that supports all orientations) using a push segue.

I think I found a nice solution.
Well, in my case I'm using a UISplitViewController as rootController in the storyboard but the idea is the same.
SubClass your rootController (In my case UISplitViewController) and Catch the shouldAutorotate() callback so you can call subviews shouldAutorotate from there.
Implement shouldAutorotate() in the View you want to Lock the Rotation
class MyUISplitViewController: UISplitViewController {
override func shouldAutorotate() -> Bool {
if ((self.viewControllers.last) != nil && (self.viewControllers.last!.topViewController) != nil){
if (self.viewControllers.last!.topViewController!.respondsToSelector("shouldAutorotate"))
{
return self.viewControllers.last!.topViewController!.shouldAutorotate()
}
}
return true
}
}
In your sub UIViewController
override func shouldAutorotate() -> Bool {
if (UIDevice.currentDevice().userInterfaceIdiom == .Phone)
{
return false
}else{
return true
}
}
If you want to check the supported orientations, you can simply do the same with supportedsupportedInterfaceOrientations()
EDIT:
Don't forget to set your "MyUISplitViewController" class in your Storyboard root viewController

Related

Auto rotate in iOS7 and iOS8

I am developing an application which is in portrait mode.
But I want one view controller should display in landscape as well as in portrait mode.
I tried the following code but it doesn't work (not called).
- (BOOL) shouldAutorotate
{
return NO;
}
- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return UIInterfaceOrientationMaskPortrait;
}
First, you need to set in your plist all the orientations your app supports, this can be done in the 'General' tab in the project under "Deployment Info", for example:
Then, you can use the method supportedInterfaceOrientations,
I assume you are presenting the view controller modally, so simply override it, on the presenting viewController, which need to be only in portrait use:
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
and in your presented viewController, which should also supports landscape, use: (or whatever orientation mask you would like)
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskAllButUpsideDown;
}
P.S - there is a different behavior for viewController that is presented modally and for a viewController that push in a navigationController stack:
modalViewController will call its own supportedInterfaceOrientations, and will support these orientations
pushedViewController will call its navigationController supportedInterfaceOrientations, and will support these orientation.
So, if you are presenting the viewController modally, you need to override its own supportedInterfaceOrientations, but if you push this viewController, you need to set some BOOL property in the navigationController, so it will know which orientations to supports.
I advise you to present this viewController modally, it's more natural to use modalViewController for different device orientations.
P.S #2: about shouldAutorotate: if it returns 'NO', than supportedInterfaceOrientations is not called, so return 'YES'. It only says, if to rotate automatically when the device rotates. if it returns 'NO', you need to explicit rotate the viewController.
Well I hope I helped and didn't write an answer that is completely not regarded to what you asked... :)

How to present a view controller in portrait or landscape, in application that is portrait-only

I have an iPhone application most of which is portrait-only, but with one view controller (a video player screen) that has to support both portrait and landscape (this is for iOS 8 only). To achieve this, I have set the app's plist to support portrait and both kinds of landscape, then subclassed UINavigationController; in this subclass I override
- (BOOL)shouldAutorotate {
return YES;
}
and
- (NSUInteger)supportedInterfaceOrientations {
if ([self.visibleViewController isKindOfClass:[MyVideoPlayerScreen class]]) {
return UIInterfaceOrientationMaskAllButUpsideDown;
} else {
return UIInterfaceOrientationMaskPortrait;
}
}
This mostly works as expected: the initial screens are all portrait-only, and remain in portrait even when the device is turned to landscape. The video player, when initially presented:
MyVideoPlayerScreen *newVC = [MyVideoPlayerScreen new];
[self.navigationController pushViewController:newVC animated:YES];
is also in portrait but will then rotate to landscape when the device is turned - all good so far.
The problem is that if I turn the device to landscape, the video player goes landscape as well, but then when I dismiss the video player screen via the back button, the underlying view controller (which is supposed to be portrait-only) is now also in landscape. If I rotate the device back to portrait the view controller rotates back to portrait as well, and it is then correctly locked in portrait-only from that point on.
How can I get the original view controller (which is supposed to be portrait-only) to automatically go back to portrait when the landscape view controller above it is popped?
This question has been asked a million times, but it seems that the fixes that were posted for it are all hacks that don't work in iOS 8 any more.
Update: I have found a "sort-of" fix for this that does work in iOS 8. In my UINavigationController subclass, I handle the <UINavigationControllerDelegate> protocol. I implemented this method:
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
if (![viewController isKindOfClass:[MyVideoPlayerScreen class]]) {
// if the current orientation is not already portrait, we need this hack in order to set the root back to portrait
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if (orientation != UIInterfaceOrientationPortrait) {
// HACK: setting the root view controller to nil and back again "resets" the navigation bar to the correct orientation
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
UIViewController *vc = window.rootViewController;
window.rootViewController = nil;
window.rootViewController = vc;
}
}
}
This at least leaves the UI in the state I want it to be in. The problem is that when the top-level view controller is dismissed and animated off-screen, the underlying view controller is still in landscape; then it suddenly jumps to portrait. Not ideal, but better than nothing.
Update 2: I should have added that I am pushing the second view controller like so:
ViewControllerPortraitLandscape *newVC = [ViewControllerPortraitLandscape new];
[self.navigationController pushViewController:newVC animated:YES];
Update 3: OK, this is totally doable, in a way that works for iOS 6 and up. The fix even kind of makes sense, although the reason for it's working does not seem to be in the documentation anywhere. Basically, in the view controller that you need to be reset to portrait when the top-level view controller is dismissed while the device is still in landscape, you just need to add this:
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
Although my subclass of UINavigationController is entirely responsible for the rotation calls, breakpoints show that supportedInterfaceOrientations is called on the underlying view controller just before the top-level is dismissed, and it's called on the navigation controller after the top-level is dismissed. So I'm inferring that this call to the view controller itself is made by iOS in order to determine what orientation the underlying view controller should be in (and it does not ask the nav controller for this); if it's not explicitly overridden it will return the all-but-upside-down parameter, so iOS just leaves it where it is, in landscape.
Turns out this is an easy fix: you can drive the entire process via a subclass of UINavigationController as I posted here (i.e. not implementing any of these rotation methods in the view controllers themselves), except that for any view controller that needs to be portrait-only, you also need to implement this:
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
With breakpoints, you can see that this method is called before the pushed view controller above it is dismissed; iOS presumably uses this call to determine what orientation the "revealed" view controller should be in (the same call to the navigation controller subclass is called after the top-level view controller is dismissed).
With this method implemented in the view controller, everything works as expected.
Be portrait EXCEPT when presenting a particular UIViewController subclass. This article helped a lot: ~~removed because of spam~~
set the Info.plist to support, portrait, landscape left, landscape right
implement application:supportedInterfaceOrientationsForWindow: like so:
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft;
}
// (I specifically want landscape left for the movie viewing)
subclass UINavigationController(the windows' rootViewController) and override like so:
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait; // enforces the “portrait everything” requirement
}
finally, I had to make sure the custom player view controller would "override" the supported orientation:
- (BOOL)shouldAutorotate
{
return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskLandscape;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeLeft;
}
Result:
UIViewController subclass presents but when dismissing the custom view controller, the presenting view controller is Portrait.
From fantageek article: "The system intersects the view controller’s supported orientations with the app’s supported orientations (as determined by the Info.plist file or the app delegate’s application:supportedInterfaceOrientationsForWindow: method) to determine whether to rotate."
I think you should change to this and try again
-(NSUInteger)supportedInterfaceOrientations {
if ([self.visibleViewController isKindOfClass:[MyVideoPlayerScreen class]])
{
return UIInterfaceOrientationMaskLandscape;
}
else
{
return UIInterfaceOrientationMaskPortrait;
}
}
Here's how you do it.
Implement these 3 methods on both presenting and presented controller:
- (BOOL)shouldAutorotate {
return NO; //-- for presented controller use YES
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscape; //-- any orientation you need
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationLandscapeRight;
}
and now you can use in the presenting controller:
[self presentViewController:presentedController animated:true completion:nil];
This way, when you go back to presenting controller, it will have the correct orientation.
My case has 3 view controller:
- first view controller: portrait
- second view controller: landscape right (has navigation controller and was presented by first view controller)
- third view controller: portrait (has navigation controller and was pushed by second view controller )
And my solution had already here. Hope this helps

Prevent autorotate for one view controller ios7?

My app can autorotate but I need one of the views to only show in portrait mode and don't know how to achieve this.
I tried this (among other things) but the view in question still rotates:
-(BOOL)shouldAutorotate
{
return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
This solution explains how to control orientation on individual view controllers, provided they are managed by a navigation controller.
In Xcode 5, create a new file of type "Objective-C category", set it's "Category" to "rotation" and choose "UINavigationController" as "Category on".
A new file couple will appear in the project, having the following names:
UINavigationController+rotation.h
UINavigationController+rotation.m
In the .m file, write the following code:
- (BOOL) shouldAutorotate
{
return [[self topViewController] shouldAutorotate];
}
- (NSUInteger) supportedInterfaceOrientations
{
return [[self topViewController] supportedInterfaceOrientations];
}
This way, the navigation controller will let the current top view controller determine the orientation policy.
Then, in each specific view controller that is managed by the navigation controller, you can override the two orientation-related methods.
For instance, if a specific view controller shall appear in portrait orientation only:
- (BOOL) shouldAutorotate
{
return NO;
}
- (NSUInteger) supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
Make sure that the desired orientation is one of those set in the project deployment info.
Hope this is sufficiently detailed and can be of help.
supportedInterfaceOrientations will work if you present your view controller as a modal view controller. It won't work if you present it as part of a navigation controller stack. If you want your view presented modally but inside a navigation controller (to have navigation items, for instance) the solution I did was to subclass UINavigationController and override the supportedInterfaceOrientations methods on my subclass.

Prevent autorotate for one view controller?

My app can autorotate but I need one of the views to only show in portrait mode and don't know how to achieve this.
I tried this (among other things) but the view in question still rotates:
// ViewController.m
-(BOOL)shouldAutorotate
{
return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
Can someone kindly point out what I'm doing wrong? Thanks.
-edit-
It's for iOS 6.1
When a UINavigationController is involved, create a category on the UINavigationController and override supportedInterfaceOrientations.
#import "UINavigationController+Orientation.h"
#implementation UINavigationController (Orientation)
- (NSUInteger)supportedInterfaceOrientations {
return [self.topViewController supportedInterfaceOrientations];
}
- (BOOL)shouldAutorotate {
return YES;
}
#end
Now, iOS containers (such as UINavigationController) do not consult their children to determine whether they should autorotate.
How to create a category
1. Add a new file (Objective c- category under cocoa touch)
2. Category : Orientation on UINavigationController
3. Add the above code to UINavigationController+Orientation.m
Swift 3 version the accepted answer:
extension UINavigationController {
open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
// Change `.portrait` to whatever your default is throughout your app
return topViewController?.supportedInterfaceOrientations ?? .portrait
}
open override var shouldAutorotate: Bool {
return true
}
}
As per the documentation.
A view controller can override the supportedInterfaceOrientations method to limit the list of supported orientations.
So we need to override shouldAutorotate and supportedInterfaceOrientation to target view controllers.
Typically, the system calls this method only on the root view controller of the window or a view controller presented to fill the entire screen.
This will work if you have very simple configuration like your target view controller is the rootViewController of window or being presented covering whole screen.
In case when configuration of target view controller is complex like embedded in some other container view controllers.
child view controllers use the portion of the window provided for them by their parent view controller and no longer participate directly in decisions about what rotations are supported.
So may be default implementation of these container view controllers not asking there children for there supportedInterfaceOrientation preference.
So to allow our target child view controller to specify there supportedIntefaceOrientation we need to tell there container view controller to do so.
You can also check my previous answer here.
and Understanding UIViewController rotation when embed in Container View Controllers.

iOS 6: How do I restrict some views to portrait and allow others to rotate?

I have an iPhone app that uses a UINavigationController to present a drill-down interface: First one view, then another, up to four levels deep. I want the first three views restricted to portrait orientation and only the last view should be allowed to rotate to landscape. When returning from the fourth view to the third and the fourth view was in landscape orientation I want everything to rotate back to portrait.
In iOS 5 I simply defined shouldAutorotateToInterfaceOrientation: in each of my view controllers to return YES for the allowable orientations. Everything worked as described above, including the return to portrait even if the device was being held in landscape orientation when returning from view controller #4 to #3.
In iOS 6 all view controllers rotate to landscape, breaking those that weren't meant to. The iOS 6 release notes say
More responsibility is moving to the app and the app delegate. Now, iOS containers (such as UINavigationController) do not consult their children to determine whether they should autorotate. [...] The system asks the top-most full-screen view controller (typically the root view controller) for its supported interface orientations whenever the device rotates or whenever a view controller is presented with the full-screen modal presentation style. Moreover, the supported orientations are retrieved only if this view controller returns YES from its shouldAutorotate method. [...] The system determines whether an orientation is supported by intersecting the value returned by the app’s supportedInterfaceOrientationsForWindow: method with the value returned by the supportedInterfaceOrientations method of the top-most full-screen controller.
So I subclassed UINavigationController, gave my MainNavigationController a boolean property landscapeOK and used this to return the allowable orientations in supportedInterfaceOrientations. Then in each of my view controllers' viewWillAppear: methods I have a line like this
[(MainNavigationController*)[self navigationController] setLandscapeOK:YES];
to tell my MainNavigationController the desired behavior.
Here comes the question: If I now navigate to my fourth view in portrait mode and turn the phone over it rotates to landscape. Now I press the back button to return to my third view which is supposed to work portrait only. But it doesn't rotate back. How do I make it do that?
I tried
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait]
in the viewWillAppear method of my third view controller, but it doesn't do anything. Is this the wrong method to call or maybe the wrong place to call it or should I be implementing the whole thing in a totally different way?
I had the same problem and found a solution that works for me.
To make it work, it is not sufficient to implement - (NSUInteger)supportedInterfaceOrientations in your UINavigationController.
You also need to implement this method in your controller #3, which is the first one to be portrait-only after popping controller #4.
So, I have the following code in my UINavigationController:
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
if (self.isLandscapeOK) {
// for iPhone, you could also return UIInterfaceOrientationMaskAllButUpsideDown
return UIInterfaceOrientationMaskAll;
}
return UIInterfaceOrientationMaskPortrait;
}
In view controller #3, add the following:
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
You don't need to add anything to your view controllers #1, #2, and #4.
This works for me, I hope it will help you.
Add a CustomNavigationController
Override these methods in it:
-(BOOL)shouldAutorotate
{
return [[self.viewControllers lastObject] shouldAutorotate];
}
-(NSUInteger)supportedInterfaceOrientations
{
return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}
Now add all orientations in the plist
In the view controller add only the required ones:
-(BOOL)shouldAutorotate
{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
these methods override the navigation controller methods
After looking through every answer in countless similar questions on SO, none of the answers worked for me, but they did give me some ideas. Here's how I ended up solving the problem:
First, make sure your Supported Interface Orientations in your project's target contain all orientations that you want for your rotating view.
Next, make a category of UINavigationController (since Apple says not to subclass it):
#implementation UINavigationController (iOS6AutorotationFix)
-(BOOL)shouldAutorotate {
return [self.topViewController shouldAutorotate];
}
#end
Import that category and the view controller that you want to be able to rotate (which I'll call RotatingViewController) to your highest level view controller, which should contain your navigation controller. In that view controller, implement shouldAutorotate as follows. Note that this should not be the same view controller that you want to rotate.
-(BOOL)shouldAutorotate {
BOOL shouldRotate = NO;
if ([navigationController.topViewController isMemberOfClass:[RotatingViewController class]] ) {
shouldRotate = [navigationController.topViewController shouldAutorotate];
}
return shouldRotate;
}
Finally, in your RotatingViewController, implement shouldAutorotate and supportedInterfaceOrientations as follows:
-(BOOL)shouldAutorotate {
// Preparations to rotate view go here
return YES;
}
-(NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAllButUpsideDown; // or however you want to rotate
}
The reason you need to do this is because iOS 6 gives control of rotation to the root view controller instead of the top view controlller. If you want an individual view's rotation to behave differently than other views in the stack, you need to write a specific case for it in the root view controller.
I don't have enough reputation to comment on #Brian's answer so I'll add my note here.
Brian mentioned that iOS6 gives the rotation control to the rootViewController - this could not only be a UINavigationController as mentioned but also a UITabBarController, which it was for me. My structure looks like this:
UITabBarController
UINavigationController
UIViewControllers ...
UINavigationController
UIViewControllers ...
So I added the methods first in a custom UITabBarController, then in a custom UINavigationController and then lastly in the specific UIViewController.
Example from the UITabBarController and UINavigationController:
- (BOOL)shouldAutorotate {
return [self.viewControllers.lastObject shouldAutorotate];
}
- (NSUInteger)supportedInterfaceOrientations {
return [self.viewControllers.lastObject supportedInterfaceOrientations];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return [self.viewControllers.lastObject shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return [self.viewControllers.lastObject preferredInterfaceOrientationForPresentation];
}
I'd like to give a partial answer to my own question. I found the following line of code, used in the viewWillAppear method of my third UIViewController, to work:
[[UIDevice currentDevice]
performSelector:NSSelectorFromString(#"setOrientation:")
withObject:(id)UIInterfaceOrientationPortrait];
But I don't really like this solution. It is using a trick to assign to a read-only property which according to Apple documentation represents the physical orientation of the device. It's like telling the iPhone to jump to the correct orientation in the hand of the user.
I am very tempted to leave this in my app since it simply works. But it doesn't feel right so I'd like to leave the question open for a clean solution.
This is I am using for orientation support in ios 6.0
-(BOOL)shouldAutorotate{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskAll;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
return UIInterfaceOrientationPortrait;
}
Being that this is a highly viewed thread. I thought I would add what I believe is the easiest answer. This works for ios8 and up
-(BOOL)shouldAutorotate
{
return YES;
}
and
-(UIInterfaceOrientationMask)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
That's it. Enjoy!
Oh, and my ViewControllers are embedded in a navigation controller, which I did not need to subclass or configure in any way.
This might not work for everyone, but it works great for me. Instead of implementing...
[(MainNavigationController*)[self navigationController] setLandscapeOK:YES];
in viewWillAppear in all of my controllers, I decided to centralize this process inside of my UINavigationController subclass by overriding the UINavigationControllerDelegate method navigationController:willShowViewController:animated:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
self.previousVCLandscapeOK = self.isLandscapeOK; // Store the current VC's orientation preference before pushing on the new VC so we can set this again from within the custom "back" method
self.isLandscapeOK = NO; // Set NO as default for all VC's
if ([viewController isKindOfClass:[YourViewController class]]) {
self.isLandscapeOK = YES;
}
}
I have found that this delegate method doesn't get called when popping a VC off of the nav stack. This wasn't an issue for me because I am handling the back functionality from within my UINavigationController subclass so that I can set the proper navigation bar buttons and actions for specific VC's like this...
if ([viewController isKindOfClass:[ShareViewController class]]) {
UIButton* backButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 57, 30)];
[backButton setImage:[UIImage imageNamed:#"back-arrow"] forState:UIControlStateNormal];
[backButton addTarget:self action:#selector(back) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem* backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
viewController.navigationItem.leftBarButtonItem = backButtonItem;
UIImageView* shareTitle = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"share-title"]];
[shareTitle setContentMode:UIViewContentModeScaleAspectFit];
[shareTitle setFrame:CGRectMake(0, 0, shareTitle.frame.size.width - 10, shareTitle.frame.size.height - 10)];
viewController.navigationItem.titleView = shareTitle;
} else if(...) {
...
}
Here is what my back method looks like to handle popping the VC off of the stack and to set the appropriate rotation preference...
- (void)back {
self.isLandscapeOK = self.previousVCLandscapeOK;
self.previousVCLandscapeOK = NO;
[self popViewControllerAnimated:YES];
}
So, as you can see, basically all that is happening is I'm first setting me two properties...
#property (nonatomic) BOOL isLandscapeOK;
#property (nonatomic) BOOL previousVCLandscapeOK;
in navigationController:willShowViewController:animated: which will determine what the supported orientations are within that VC that is about to be presented. When popping a VC, my custom "back" method is being called and I'm then setting the isLandscapeOK to what was stored via the previousVCLandscapeOK value.
As I said, this might not work for everyone, but it works great for me and I don't have to worry about adding code to each of my view controllers, I was able to keep it all centralized in the UINavigationController subclass.
Hope this helps someone as it did me.
Thanks, Jeremy.
Go to you Info.plist file and make the change
You want to Force iOS 6 app portrait only then you can add to a UIViewController subclass below methods
- (BOOL)shouldAutorotate {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
return YES;
} else {
return NO;
}
}
- (NSUInteger)supportedInterfaceOrientations {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
return UIInterfaceOrientationMaskAll;
} else {
return UIInterfaceOrientationMaskPortrait;
}
}
I wanted to have all my VCs locked to portrait orientation except one. This is what worked for me.
Add support for all orientations in the plist file.
In the root view controller, detect the kind of view controller thats on top of the window and set the orientation of the app accordingly in the supportedInterfaceOrientations method. For example, I needed my app to rotate only when the webview was on top of the stack. Here's what I added in my rootVC :
-(NSUInteger)supportedInterfaceOrientations
{
UIViewController *topMostViewController = [[Utils getAppDelegate] appNavigationController].topViewController;
if ([topMostViewController isKindOfClass:[SVWebViewController class]]) {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
return UIInterfaceOrientationMaskPortrait;
}
I don't have enough reputation to answer #Ram S question under #micmdk reply so I'll add my note here.
When you use UITabbarController, try to change self.viewControllers.lastObject in
#micmdk's code to self.selectedViewController like this:
- (BOOL)shouldAutorotate {
return [self.selectedViewController shouldAutorotate];
}
- (NSUInteger)supportedInterfaceOrientations {
return [self.selectedViewController supportedInterfaceOrientations];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
return [self.selectedViewController shouldAutorotateToInterfaceOrientation:toInterfaceOrientation];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return [self.selectedViewController preferredInterfaceOrientationForPresentation];
}
You can implement and override shouldAutorotate() and supportedInterfaceOrientations var in all of your View Controller classes that should be presented in a different orientations than ones defined in PLIST of your app.
However, in a nontrivial User Interface you might face a problem to add it in dozens of classes and you do not want to make all of them subclass of several common that supports it (MyBaseTableViewController, MyBaseNavigationController and MyBaseTabBarController).
Since you cannot override those method/var on UIViewController directly, you may do that on its subclasses that are typically base classes of yours like UITableViewController, UINavigationController and UITabBarController.
So you may implement a few extensions and still setup MyPreciousViewController to show in a different orientations than all others like this Swift 4 code snippet:
extension UITableViewController {
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if let last = self.navigationController?.childViewControllers.last,
last != self {
return last.supportedInterfaceOrientations
} else {
return [.portrait]
}
}
}
extension MyPreciousViewController {
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return [.portrait,.landscape]
}
}
extension UINavigationController {
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return [.portrait]
}
}
extension UITabBarController {
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return [.portrait]
}
}
I've solved the same kind of issue.
If you are using the UINavigationController to push the view controllers, you have to set the methods below.
extension UINavigationController{
override open var shouldAutorotate: Bool {
if topViewController != nil && (topViewController?.isKind(of: LogInViewController.self))!
{
return true
}
return false
}
override open var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if topViewController != nil && (topViewController?.isKind(of: LogInViewController.self))!
{
return .portrait
}
return .landscapeRight
}
override open var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
if topViewController != nil && (topViewController?.isKind(of: LogInViewController.self))!
{
return .portrait
}
return .landscapeRight
}
}
In place of LoginViewController use which UIViewController you want show. In my case, I want to show the LoginViewController in the Portrait mode other ViewControllers in landscape mode.
Please use the following method to solve this issue
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
return only the orientation you want!!!

Resources