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.
Ok, folks, I will post my solution.
What I have:
- A view based application, with several view controllers. (It was navigation based, but I had to make it view based, due to orientation issues).
- All view controllers are portrait, except one - landscapeLeft.
Tasks:
- One of my view controllers must automatically rotate to landscape, no matter how the user holds the device. All other controllers must be portrait, and after leaving the landscape controller, the app must force rotate to portrait, no matter, again, how the user holds the device.
- This must work as on IOS 6.x as on IOS 5.x
Go!
(Update Removed the macros suggested by @Ivan Vučica)
In all your PORTRAIT view controllers override autorotation methods like this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
}
-(BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
You can see the 2 approaches: one for IOS 5 and another For IOS 6.
The same for your LANDSCAPE view controller, with some additions and changes:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
[image_signature setImage:[self resizeImage:image_signature.image]];
return (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
-(BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
[image_signature setImage:[self resizeImage:image_signature.image]];
return UIInterfaceOrientationMaskLandscapeLeft;
}
ATTENTION: to force autorotation in IOS 5 you should add this:
- (void)viewDidLoad{
[super viewDidLoad];
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 6.0)
[[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationLandscapeLeft animated:NO];
}
Analogically, after you leave the LANDSCAPE controller, whatever controller you load, you should force again autorotation for IOS 5, but now you will use UIDeviceOrientationPortrait
, as you go to a PORTRAIT controller:
- (void)viewDidLoad{
[super viewDidLoad];
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 6.0)
[[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationPortrait animated:NO];
}
Now the last thing (and it's a bit weird) - you have to change the way you switch from a controller to another, depending on the IOS:
Make an NSObject class "Schalter" ("Switch" from German).
In Schalter.h say:
#import <Foundation/Foundation.h>
@interface Schalter : NSObject
+ (void)loadController:(UIViewController*)VControllerToLoad andRelease:(UIViewController*)VControllerToRelease;
@end
In Schalter.m say:
#import "Schalter.h"
#import "AppDelegate.h"
@implementation Schalter
+ (void)loadController:(UIViewController*)VControllerToLoad andRelease:(UIViewController*)VControllerToRelease{
//adjust the frame of the new controller
CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
CGRect windowFrame = [[UIScreen mainScreen] bounds];
CGRect firstViewFrame = CGRectMake(statusBarFrame.origin.x, statusBarFrame.size.height, windowFrame.size.width, windowFrame.size.height - statusBarFrame.size.height);
VControllerToLoad.view.frame = firstViewFrame;
//check version and go
if (IOS_OLDER_THAN_6)
[((AppDelegate*)[UIApplication sharedApplication].delegate).window addSubview:VControllerToLoad.view];
else
[((AppDelegate*)[UIApplication sharedApplication].delegate).window setRootViewController:VControllerToLoad];
//kill the previous view controller
[VControllerToRelease.view removeFromSuperview];
}
@end
NOW, this is the way you use Schalter ( suppose you go from Warehouse controller to Products controller ) :
#import "Warehouse.h"
#import "Products.h"
@implementation Warehouse
Products *instance_to_products;
- (void)goToProducts{
instance_to_products = [[Products alloc] init];
[Schalter loadController:instance_to_products andRelease:self];
}
bla-bla-bla your methods
@end
Of course you must release instance_to_products
object:
- (void)dealloc{
[instance_to_products release];
[super dealloc];
}
Well, this is it. Don't hesitate to downvote, I don't care. This is for the ones who are looking for solutions, not for reputation.
Cheers!
Sava Mazare.
Best Answer
If the modal controller was in landscape orientation before dismissal, the presenting ViewController may not return to the origin orientation (portrait). The problem is because the AppDelegate supportedInterfaceOrientationsForWindow method is called before the controller is actually dismissed and the presented controller check still returns Landscape mask.
Set a flag to indicate whether the (modal) presented view controller will be displayed or not.
And in the modal presented ViewController set the orientation according to the flag: When the modal ViewController is presented - return Landscape. When it is dismissed then return portrait
Last step - from your AppDelegate call the modal presented ViewController for its orientation. I am just checking the currently presented ViewController and call the supportedInterfaceOrientations on it
For more info check this link