I NEED: rotate device programmatically from portrait to landscape compatible for iOS6 and iOS5.
THE PROBLEM: I cannot use [UIDevice setOrientation] function on ios6.
WHAT I HAVE: the code for iOS6:
- (BOOL) shouldAutorotate
{
return YES;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeLeft;
}
the code for iOS5:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
So, I need write the code that rotate on iOS5:
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// [[UIDevice currentDevice] setOrientation] - I cannot use it
// ???
}
I achieved this by set Status bar orientation, try execute in code:
[[sharedApplication] setStatusBarHidden:YES];
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight];
and when you need portrait mode, set status bar to setStatusBarHidden:NOand again set statusbar orientation to portrait UIInterfaceOrientationPortrait.
I gave an app with say 10 view controllers. I use navigation controller to load/unload them.
All but one are in portrait mode. Suppose the 7th VC is in landscape. I need it to be presented in landscape when it gets loaded.
Please suggest a way to force the orientation go from portrait to landscape in IOS 6 (and it will be good to work in IOS 5 as well).
Here is how I was doing it BEFORE IOS 6:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
UIViewController *c = [[[UIViewController alloc]init] autorelease];
[self presentModalViewController:c animated:NO];
[self dismissModalViewControllerAnimated:NO];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
Presenting and dismissing a modal VC was forcing the app to review its orientation, so shouldAutorotateToInterfaceOrientation was getting called.
What I have have tried in IOS 6:
- (BOOL)shouldAutorotate{
return YES;
}
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskLandscape;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
return UIInterfaceOrientationLandscapeLeft;
}
On load, the controller keeps staying in portrait. After rotating the device, the orientation changes just ok. But I need to make the controller to rotate automatically to landscape on load, thus the user will have to rotate the device to see the data correctly.
Another problem: after rotating the device back to portrait, the orientation goes to portrait, although I have specified in supportedInterfaceOrientations only UIInterfaceOrientationMaskLandscape. Why it happens?
Also, NONE of above 3 methods are getting called.
Some (useful) data:
In my plist file I have specified 3 orientations - all but upside down.
The project was started in Xcode 4.3 IOS 5. All classes including xibs were created before Xcode 4.5 IOS 6, now I use the last version.
In plist file the status bar is set to visible.
In xib file (the one I want to be in landscape) the status bar is "None", the orientation is set to landscape.
Any help is appreciated. Thanks.
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.
This should work, it's similar to the pre-iOS 6 version, but with a UINavigationController:
UIViewController *portraitViewController = [[UIViewController alloc] init];
UINavigationController* nc = [[UINavigationController alloc] initWithRootViewController:portraitViewController];
[self.navigationController presentModalViewController:nc animated:NO];
[self.navigationController dismissModalViewControllerAnimated:NO];
I'm calling this before I'm pushing the next UIViewController. It will force the next pushed UIViewController to be displayed in Portrait mode even if the current UIViewController is in Landscape (should work for Portrait to Landscape too). Works on iOS 4+5+6 for me.
I think that best solution is to stick to official apple documentation. So according to that I use following methods and everything is working very well on iOS 5 and 6.
In my VC I override following methods:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return UIInterfaceOrientationIsPortrait(interfaceOrientation);
}
Methods for iOS 6, first method returns supported orientation mask (as their name indicate)
-(NSUInteger)supportedInterfaceOrientations{
return UIInterfaceOrientationMaskPortrait;
}
second one thats tells your VC which is preferred interface orientation when VC is going to be displayed.
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationPortrait;
}
Just change Portrait for orientation that you want ;)
This solution is working smooth, I don't like the idea of creating macros and other stuff, that goes around this simple solution.
Hope this help...
I had the same problem, 27 views in my application from which 26 in portrait and only one in all orientations ( an image viewer :) ).
Adding the macro on every class and replace the navigation wasn't a solution I was comfortable with...
So, i wanted to keep the UINavigationController mechanics in my app and not replace this with other code.
What to do:
#1 In the application delegate in method didFinishLaunchingWithOptions
if ([[UIDevice currentDevice].systemVersion floatValue] < 6.0)
{
// how the view was configured before IOS6
[self.window addSubview: navigationController.view];
[self.window makeKeyAndVisible];
}
else
{
// this is the code that will start the interface to rotate once again
[self.window setRootViewController: self.navigationController];
}
#2
Because the navigationController will just responde with YES for autorotation we need to add some limitations:
Extend the UINavicationController -> YourNavigationController and link it in the Interface Builder.
#3 Override the "anoying new methods" from navigation controller.
Since this class is custom only for this application it can take responsibility
for it's controllers and respond in their place.
-(BOOL)shouldAutorotate {
if ([self.viewControllers firstObject] == YourObject)
{
return YES;
}
return NO;
}
- (NSUInteger)supportedInterfaceOrientations {
if ([self.viewControllers firstObject] == YourObject)
{
return UIINterfaceOrientationMaskLandscape;
}
return UIInterfaceOrientationMaskPortrait;
}
I hope this will help you,
From the iOS 6 Release Notes:
Now, iOS containers (such as UINavigationController) do not consult their children to determine whether they should autorotate.
Does your rootViewController pass the shouldAutoRotate message down the ViewController hierarchy to your VC?
I used the same method as OP pre-ios6 (present and dismiss a modal VC) to show a single view controller in landscape mode (all others in portrait). It broke in ios6 with the landscape VC showing in portrait.
To fix it, I just added the preferredInterfaceOrientationForPresentation method in the landscape VC. Seems to work fine for os 5 and os 6 now.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
- (BOOL)shouldAutorotate
{
return NO;
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return UIInterfaceOrientationLandscapeLeft;
}
Hey guys after tryng a lot of different possible solutions with no success i came out with the following solution hope it helps!.
I prepared a recipe :).
Problem:
you need change orientation of viewcontrollers using navigationcontroller in ios 6.
Solution:
step 1. one initial UIviewcontroler to trigger modal segues to landscape and
portrait UInavigationControllers as picture shows....
more deeply in UIViewController1 we need 2 segues actions according to global variable at Appdelegate....
-(void)viewDidAppear:(BOOL)animated{
if([globalDelegate changeOrientation]==0){
[self performSegueWithIdentifier:#"p" sender:self];
}
else{
[self performSegueWithIdentifier:#"l" sender:self];
}
}
also we need a way back to portrait &| landscape....
- (IBAction)dimis:(id)sender {
[globalDelegate setChangeOrientation:0];
[self dismissViewControllerAnimated:NO completion:nil];
}
step 2. the first Pushed UiViewControllers at each NavigationController goes
with...
-(NSUInteger)supportedInterfaceOrientations{
return [self.navigationController supportedInterfaceOrientations];
}
-(BOOL)shouldAutorotate{
return YES;
}
step 3. We overwrite supportedInterfaceOrientations method at subclass of UInavigationController....
in your customNavigationController we have .....
-(NSUInteger)supportedInterfaceOrientations{
if([self.visibleViewController isKindOfClass:[ViewController2 class]]){
return UIInterfaceOrientationMaskPortrait;
}
else{
return UIInterfaceOrientationMaskLandscape;
}
}
step 4. At storyboard or by code, set wantsFullScreenLayout flag to yes, to both portrait and landscape uinavigationcontrollers.
Try segueing to a UINavigationController which uses a category or is subclassed to specify the desired orientation, then segue to the desired VC. Read more here.
As an alternative you can do the same using blocks:
UIViewController *viewController = [[UIViewController alloc] init];
viewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:viewController animated:NO completion:^{
[self dismissViewControllerAnimated:NO completion:nil];
}];
Also, call it before pushing the new view.
Go to you Info.plist file and make the change
I had the same problem. If you want to force a particular view controller to appear in landscape, do it right before you push it into the navigation stack.
UIInterfaceOrientation currentOrientation = [[UIApplication sharedApplication] statusBarOrientation];
if (currentOrientation == UIInterfaceOrientationPortrait ||
currentOrientation == UIInterfaceOrientationPortraitUpsideDown)
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeLeft];
UIViewController *vc = [[UIViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
[vc release];
I solved it by subclassing UINavigationController and overriding the supportedInterfaceOrientations of the navigation Controller as follow:
- (NSUInteger)supportedInterfaceOrientations
{
return [[self topViewController] supportedInterfaceOrientations];
}
All the controllers implemented supportedInterfaceOrientations with their desired orientations.
I have used the following solution. In the one view controller that has a different orientation than all the others, I added an orientation check in the prepareForSegue method. If the destination view controller needs a different interface orientation than the current one displayed, then a message is sent that forces the interface to rotate during the seque.
#import <objc/message.h>
...
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if(UIDeviceOrientationIsLandscape(self.interfaceOrientation))
{
UIInterfaceOrientation destinationOrientation;
if ([[segue destinationViewController] isKindOfClass:[UINavigationController class]])
{
UINavigationController *navController = (UINavigationController *)[segue destinationViewController];
destinationOrientation = [navController.topViewController preferredInterfaceOrientationForPresentation];
} else
{
destinationOrientation = [[segue destinationViewController] preferredInterfaceOrientationForPresentation];
}
if ( destinationOrientation == UIInterfaceOrientationPortrait )
{
if ([[UIDevice currentDevice] respondsToSelector:#selector(setOrientation:)])
{
objc_msgSend([UIDevice currentDevice], #selector(setOrientation:), UIInterfaceOrientationPortrait );
}
}
}
}
I am quite new to iOS and I am trying desperately to get orientation changes working in my app. After researching here's what I do:
In my app I have a NavigationController managing seven UIViewController subclasses.
In the projects summary tab I activated all 4 device orientations.
Each UIViewcontroller subclass has a xib file, all xib files have "autoresize subviews" activated.
The UIViewController subclasses all have:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait ||
interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
interfaceOrientation == UIInterfaceOrientationLandscapeRight );
}
they also all have:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
and:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
implemented with an NSLog(...) statements (never printed, debugger also never entering these methods).
Also I was trying to use:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
BOOL getOrientationUpdates = [[UIDevice currentDevice] isGeneratingDeviceOrientationNotifications];
NSLog(#"will receive orientation notifications: %#", getOrientationUpdates?#"YES":#"NO");
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
with
-(void)orientationChanged: (NSNotification*) notification
{
NSLog(#"orientationChanged");
}
and
[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] removeObserver:self];
respectively.
when I do beginGeneratingDeviceOrientationNotifications etc. in the AppDelegate's - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
method, orientationChanged: is called once on startup but never again however I rotate the device, when I do it in one of the UIViewController subclasses it is never called!
So far, all I want to achieve is getting orientation notifications to rotate an UIImageView and UIImage (without any layout changes in the different orientations).
UIDeviceOrientation o = [UIDevice currentDevice].orientation;
always returns UIDeviceOrientationPortrait
It might be that I missed something in the docs or on stackoverflow, but I obviously cannot figure out what I need to do/add to get it working in my setup. also I am quite new to stackoverflow, so I hope my post is not violating any platform conventions.
Any help/hints are greatly appreciated. Thank you so much!
EDIT:
getOrientationUpdates is always YES, which appears strange to me as the notification callback selector is never called when I rotate it!
EDIT: in my AppDelegate's didFinishLaunchingWithOptions I am doing:
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.regScreenController = [[RegistrationScreenController alloc] initWithNibName:#"RegistrationScreenController" bundle:nil];
navCtrl = [[UINavigationController alloc]initWithRootViewController:self.regScreenController];
[navCtrl setNavigationBarHidden:YES];
self.window.rootViewController = self.regScreenController;
[self.window addSubview:navCtrl.view];
[self.window makeKeyAndVisible];
return YES;
See if you are setting the self.window.rootViewController in your AppDelegate's didFinishLaunchingWithOptions: method, because if you're adding only subviews to the window the orientation change notification does not fire.
I have created a simple navigation application. I allow all orientations for the application.
Problem is as follows
I am in landscape orientation. then i navigate from RootViewController to a UIViewController For showing the PDF. When I am in UiviewControoler i change orientation to portrait. and come back to the RootViewController. At this time the RootViewController is in landscape mode itself and it Shows whole UI badly.
I really do not know what to search on net. still i tried to search but couldn't got my answer.Can anyone tell me How to fix this problem?
First You declare Boolean type variable in app delegate file and then set property and synthesize in .m file. In app-delegate.m file u
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration{
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
{
MidwestTestAppDelegate *appDelegate = (MidwestTestAppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.isLandscapeLeft = TRUE;
}
else
{
MidwestTestAppDelegate *appDelegate = (MidwestTestAppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.isLandscapeLeft = FALSE;
}
}
in .m file u use this function which give u orientation is enable or not. similarly u do for view controller.
I have been searching for an answer to this, but cannot come up with anything. Apparently, iPhone SDK 3.0 made it possible that UIImagePickerController can be displayed in landscape mode - but I am not finding any method that will allow this. I would think that if the application is in landscape by default it would automatically adjust the image controller, but that is not working for me.
Thanks for any help!
No need to subclass; simply override the modalPresentationStyle property.
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.modalPresentationStyle = UIModalPresentationFormSheet;
[viewController presentViewController:picker animated:YES completion:NULL];
I haven't checked whether this is illegal, but it worked for me.
If you want the UIImagePickerController to start(and stay) in Landscape orientation code:
//Initialize picker
UIImagePickerController * picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
//set Device to Landscape. This will give you a warning. I ignored it.
//warning: 'UIDevice' may not respond to '-setOrientation:'
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
//Set Notifications so that when user rotates phone, the orientation is reset to landscape.
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
//Refer to the method didRotate:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(didRotate:)
name:#"UIDeviceOrientationDidChangeNotification" object:nil];
//Set the picker source as the camera
picker.sourceType = UIImagePickerControllerSourceTypeCamera;
//Bring in the picker view
[self presentModalViewController:picker animated:YES];
The method didRotate:
- (void) didRotate:(NSNotification *)notification
{
//Maintain the camera in Landscape orientation
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
}
If you just need to get rid of the warning try
#interface UIDevice ()
-(void)setOrientation:(UIDeviceOrientation)orientation;
#end
I've developed a UIImagePicker class in landscape mode. Works great for applications I've developed: hope it works for you too:
GitHub: https://github.com/imaginaryunit/iOSLandscapeThreadedImagePicker.git
I have an all-landscape app using UIImagePickerController too. Please be noted that if you call UIImagePickerController in Landscape mode, your app is possible to be rejected by Apple Review Team.
I devised a simple work around this issue which make use the shouldAutoRotate delegate. Apple approves this method for an all-landscape app.
See here for the details and downloadable full project source code.
Make a category of UINavigationController and add this method
- (BOOL)shouldAutorotate
{
return NO;
}
Subclass UIImagePickerController and override modalPresentationStyle as follows:
- (UIModalPresentationStyle)modalPresentationStyle
{
if([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)
{
return UIModalPresentationFormSheet;
}
return [super modalPresentationStyle];
}
The image-picker is a form-sheet now and no longer in fullscreen-mode, but it looks good in landscape-mode.
This should be totally app-store-safe.
This works for the gallery, not for taking pictures.
I solved this problem as follows: after each change in orientation, I simple re-create picker. Try this. Differently is too crooked...
I am developing a class that tries its best to work in landscape mode.
Check it out on GitHub: RACameraController