I have a case where a portrait only mode view needs to be pushed into a navigation controller which has a landscape mode view as its current view.
Although I have reimplemented
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
but it is still pushing the view in landscape mode. I have also tried the following way, but even this is not working.
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:YES];
}
I tried looking into other related questions but did not find anything.
Any idea how I can solve this?
Thanks!
Your best bet is to just use a modal view controller instead which forces the view to be in portrait regardless of device orientation.
If you want to wrap a navigation controller around it to keep styling consistent, look at Apple's Core Data Recipes example for how they do this when you add a new recipe.
Related
I am looking to have one view in my app have landscape orientation. I have managed to get the view to stay in landscape when rotated manually, but if the device is already portrait, it stays portrait, regardless of its supported orientation (set using supportedInterfaceOrientations method) . Is there a way to get the view to rotate automatically? I have tried:
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO];
but this doesn't work.
Any suggestions would be greatly appreciated!
One way to do this is by overriding preferredInterfaceOrientationForPresentation but in order for that to be called the viewController has to be presented (as in modal) and not pushed as mentioned here:
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
NSLog(#" preferred called");
return UIInterfaceOrientationPortrait;
}
In order to present your viewController in a UINavigationController use:
UINavigationController *presentedNavController = [[UINavigationController alloc] initWithRootViewController:protraitViewController];
[self presentViewController:presentedNavController animated:YES completion:nil];
To make UINavigationController respect your current viewController's orientation preferences use this simple category instead of sub-classing.
Also, this part of Apple's documentation is a good read for understanding iOS orientation handling better.
Define the following in the UIViewController for your landscape-only view:
- (UIInterfaceOrientation) supportedInterfaceOrientations
{ return UIInterfaceOrientationLandscapeLeft; } // or right or both
This should prevent your view from ever appearing in portrait. From iOS documentation:
Declaring a Preferred Presentation Orientation
When a view controller
is presented full-screen to show its content, sometimes the content
appears best when viewed in a particular orientation in mind. If the
content can only be displayed in that orientation, then you simply
return that as the only orientation from your
supportedInterfaceOrientations method.
In my Application I'm using a navigation controller to mange views. My login page support both portrait and landscape views. When user logged in my second view is home and it support only landscape mode. What I want to do is when user login to the home using portrait view home page should appear in landscape view even though the device in portrait.
So what I did was I change the status bar orientation in to landscape int the home page's viewWillAppear method as follows;
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationLandscapeRight animated:NO];
UIDeviceOrientation orien = [[UIDevice currentDevice] orientation];
}
also I have override the shouldAutorotateToInterfaceOrientation as follows
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
My problem is even the status bar changed to landscape my UIViewController (home) is remains in landscape mode. When i'm debugging I found that even I change the status bar orientation to landscape,[[UIDevice currentDevice] orientation] returns portrait. I went through internet whole day. And implement lot of solutions proviede by other but my whole day wasted. can some one guide me to solve these issue.
you just need to like:-
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight) {
return YES;
}
else
{
return NO;
}
}
for particular class you want to open landscape Only
in ios6:-
-
(BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscape;
}
Apple does not want you to force the orientation of the device. There is a trick though.
Unfortunately I do not have access to my code.
1. Your app in general supports all orientations.
2. All view controllers only return their supported interface orientation in their overwrites respectivly (in supportedInterfaceOrientations).
3. All view controllers return YES in shouldAutorotateToInterfaceOrientation only for their supported orientations.
That is fine. But it would still require the user to actually rotate the device. Otherwise the whole orientation change mechanism would not be invoked.
Now, when you want to force the orientation change, do the following:
4. Use setStatusBarOrientation to set the orientation before the next view controller is displayed.
That alone would not do anything. Plus it would not take any effect if the next view controller is pushed. It would work fine only when the next view controller is presented modally.
5a. So if you want to present the rotated view controller modally, then do it.
5b. If you still need to push it then:
5b1. Create an empty UIViewController instance. alloc/init will do.
5b2. Present it modally
5b3. Dismiss it modally
Now, the new view controller was not even visible to the user but the device - here comes the magic - is rotated now.
5c4. Next push the view controller that you want to display roated.
And vice versa on your way back :)
All the above gets more complicated when you use a tab bar. Do you use a tab bar?
I managed to get that working with a tab bar which I had to subclass to overwrite its rotation methods. In an app without tab bar I subclassed UIApplication (!) but don't rembember wether that was really required or wether I did that out of convenience (instead of aplying the changes to 50+ view controllers). But in principle the above is it that does the trick.
PS: You find a more detailled answer here along with code samples:
Presenting Navigation Controller in Landscape mode is not working ios 6.0
You can try with
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
and
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)toInterfaceOrientation {
return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
}
or try presenting it as a Modal, rather than pushing it.
My application is primarily portrait, however there is one view that REQUIRES a landscape orientation.
My views are contained within a UINavigationController, which (apparently) is the cause of this issue.
All UIViewControllers except one have this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
The UIViewController that requires Landscape has this:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
Now, what happens is when the user reaches the landscape UIViewController, it is shown in portrait. The user can then rotate their phone and it displays in landscape as I want it to (locking to landscape). The user then progresses onwards to a portrait UIViewController and the same happens: it start in landscape, then they rotate their phone and it becomes portrait again (and locks to portrait).
It seems orientation locking is allowed between UIViewControllers, however auto-rotation / programmatically changing the orientation is somehow blocked.
How do I force the phone to update to the correct orientation?
There is a temporary solution: I can detect the orientation of the device and show a message asking them to rotate the device if it is not correct, however this is not optimal.
I had the same requirement for one of my applications!!!
luckily I found a solution!
In order to keep main viewcontroller landscape, no matter from what orientation it was popped/pushed, I did the following thing: (in viewWillAppear:)
//set statusbar to the desired rotation position
[[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationLandscapeLeft animated:NO];
//present/dismiss viewcontroller in order to activate rotating.
UIViewController *mVC = [[[UIViewController alloc] init] autorelease];
[self presentModalViewController:mVC animated:NO];
[self dismissModalViewControllerAnimated:NO];
P.S.Tested on sdk 3.2.5 ios 5.0.1.
P.S. On iOS 8 previous answer results some screen flickering and also - it is not stable (In some cases It does not work for me anymore.) So, for my needs, I changed the code to: (ARC)
//set statusbar to the desired rotation position
[[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationLandscapeLeft animated:NO];
[self.navigationController presentViewController:[UIViewController new] animated:NO completion:^{
dispatch_after(0, dispatch_get_main_queue(), ^{
[self.navigationController dismissViewControllerAnimated:NO completion:nil];
});
}];
//I added this code in viewDidDissapear on viewController class, which will be popped back.
Hopefully it will help!
This might help. You can call the following method upon appearing, where appropriate. e.g. in -viewWillAppear:animated
attemptRotationToDeviceOrientation
Attempts to rotate all windows to the orientation of the device.
+ (void)attemptRotationToDeviceOrientation
Discussion
Some view controllers may want to use app-specific conditions to
determine the return value of their implementation of the
shouldAutorotateToInterfaceOrientation: method. If your view
controller does this, when those conditions change, your app should
call this class method. The system immediately attempts to rotate to
the new orientation. A rotation occurs so long as each relevant view
controller returns YES in its implementation of the
shouldAutorotateToInterfaceOrientation: method.
Availability
Available in iOS 5.0 and later.
http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIViewController_Class/Reference/Reference.html
Use this,
[[UIDevice currentDevice]performSelector:#selector(setOrientation:) withObject:(__bridge id)((void *)UIInterfaceOrientationLandscapeRight)];
I have two views, on first view i have multiple buttons, i wanted that view to be landscape right so i put this code :
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
it works fine as my application starts in landscape right mode. the buttons on this view pushes user to second view which i wanted to be a portrait mode. so i put that code in second view but its not working as i wanted.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
its showing my the orientation which i had on previous view. should i have to put something on viewdidload to make it works? please help. thanks
It's a bit a hack, but here it is. In the -(void)viewDidLoad of the viewController that you want to force portrait for do the following:
UIViewController *viewController = [[UIViewController alloc] init];
[self presentModalViewController:viewController animated:NO];
[self dismissModalViewControllerAnimated:NO];
[viewController release];
This basically forces portrait, by presenting a controller (which only supports portrait by default).
You should use one orientation for all view controllers. Otherwise you may have some problems. For example in your case imagine that the user has switched to the second view and has changed the orientation to UIInterfaceOrientationPortrait. Now he returns to the first screen and all buttons are on the wrong positions! Actually the problem is that the orientation will not change to UIInterfaceOrientationLandscapeRight back as you expect. It happens because shouldAutorotateToInterfaceOrientation is not called after viewWillAppear is triggered. So you have to code some dirty hacks to force orientation change. It is not a good solution.
By the way, how do you change your controllers? If you are using addSubview, then your second controller's shouldAutorotateToInterfaceOrientation will not be triggered at all. When using addSubview you should handle it by yourself.
I'm developing an iPhone application that has several nibs, and should be landscape only.
The application is set to start in landscape mode via its Info.plist file.
I have two view controllers:
FirstViewController and SecondViewController.
For each of these I have a nib file, where the view is in landscape. Both view controllers are added to my MainView nib as outlets, and their views are lazily initialized.
When the application loads, the first view displays in landscape, as expected. However, when I switch to the second view, the device (or simulator) remains in landscape, but the view is rotated, as if the device were in portrait mode, braking my interface.
In both UIViewController classes I have the following code:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return interfaceOrientation == UIInterfaceOrientationLandscapeRight;
}
and to switch views, in my app delegate I'm doing:
[viewController.view removeFromSuperview];
[window addSubview:secondViewController.view];
where viewController and secondViewController are the two outlets where the view controllers are connected.
This is how the second view looks in IB:
alt text http://img27.imageshack.us/img27/4898/picture1ni.png
and this is how it looks in the simulator:
alt text http://img402.imageshack.us/img402/4866/picture2wt.png
Why is that the second view is displaying in landscape but with the interface rotated?
I wouldn't like to deal with transform properties, since that seems overkill.
I starred this question hoping someone would give you an insightful response and I'd learn something.. sadly I'm afraid that you might need to use transforms to get this to work properly. Here's the code I've been using lately to solve the problem:
- (void)forceLandscapeForView:(UIView *)theView {
theView.transform = CGAffineTransformMakeRotation(degreesToRadian(90));
theView.bounds = CGRectMake(0, 0, 480, 320);
theView.center = CGPointMake(160, 240);
[theView setNeedsLayout];
[theView setNeedsDisplay];
}
Then when you're adding your new view, check the current orientation and if necessary force the rotation:
if (!UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation)) {
[self forceLandscapeForView:_activeViewController.view];
}
Then of course you'll want to respond appropriately to shouldAutorotateToInterfaceOrientation in each of your view controllers:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}
I would love to hear about alternate solutions if this isn't all necessary. There is also one caveat I've noticed with this setup: if you have a transition between views, and you rotate the phone during that transition, it's possible for the views orientations to get flipped or "stuck" on the wrong landscape orientation, such that you need to turn the phone over (landscape-right vs landscape-left) as you navigate between views.
it is just a suggestion but you can try to return NO in the shouldAotorotate method for the second view. Or try to make it in the portrait view in the IB. It seems that your view was loaded correctly(in the landscape mode) but then received shouldAutorotate message and had been rotated by 90 degrees.