UITabBar identifying portrait or landscape orientation - iphone

While, for the most part, orientation is working properly for my app, I'm having an issue testing on my iPad 1. If I have the device tipped at a relatively low angle, there are times while navigating through the tabs that the tab bar appears in landscape mode, but the page calls a portrait mode uiview and then tries to render it in landscape mode, screwing up my UI.
I'm trying to figure out if there is a method to lock down "if the tab bar appears in landscape mode, always call the landscape UIViews and if in portrait mode, always call the portrait UIView."
On each view controller I've set the following:
- (void)viewDidLoad
{
[super viewDidLoad];
// iPad-specific condition here
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
if (UIDeviceOrientationIsPortrait([UIDevice currentDevice].orientation)){
self.view = self.portraitViewiPad;
}
else {
self.view = self.landscapeViewiPad;
}
}
}
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
// iPad-specific condition here
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
if (toInterfaceOrientation == UIInterfaceOrientationPortrait || toInterfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) {
//show portrait XIB here
self.view = self.portraitViewiPad;
} else {
//show landscape XIB here
self.view = self.landscapeViewiPad;
}
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
// iPad-specific interface here
return YES;
}
else
{
// For iPhone and iPod touch interface
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
}
I've also adjusted the app delegate using the method below thinking that could address the issue:
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
//CALLS RELOAD METHODS HERE AND EACH UIVIEW IS PROPERLY BEING CALLED
}
UPDATE:
Corrected this issue by checking the orientation of the status bar and displaying the correct uiview accordingly. Here's how I updated my viewDidLoad methods:
if ([[UIApplication sharedApplication] statusBarOrientation] == UIDeviceOrientationLandscapeLeft){
NSLog(#"Left landscape detected");
self.view = self.landscapeViewiPad;
} else if ([[UIApplication sharedApplication] statusBarOrientation] == UIDeviceOrientationLandscapeRight){
NSLog(#"Right landscape detected");
self.view = self.landscapeViewiPad;
} else if ([[UIApplication sharedApplication] statusBarOrientation] == UIDeviceOrientationPortrait){
NSLog(#"Portrait orientation detected");
self.view = self.portraitViewiPad;
} else if ([[UIApplication sharedApplication] statusBarOrientation] == UIDeviceOrientationPortraitUpsideDown){
NSLog(#"Upsidedown Portrait detected");
self.view = self.portraitViewiPad;
}

I think that you don't want to do test [[UIDevice currentDevice] orientation]. As the documentation notes that value can be different than the actual orientation of your app's UI. I think you'll want to rely on the calls to [UIViewController shouldRotateTo...] and [UIViewController willRotateTo...].

Related

iPhone interface orientation change not returning to portrait orientation

So I have a view that I present modally when the interface orientation changes to landscape. However when the orientation returns to portrait and the modal view dismisses itself, the tableview from the initial view remains in landscape orientation (this table view must be only in portrait orientation)
Here is the code :
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return ((interfaceOrientation == UIInterfaceOrientationPortrait) || (interfaceOrientation == UIInterfaceOrientationLandscapeLeft) || (interfaceOrientation == UIInterfaceOrientationLandscapeRight) );
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
if ((toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) || (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)) {
[self performSegueWithIdentifier:#"showCatChart" sender:self];
}
if (toInterfaceOrientation == UIInterfaceOrientationPortrait) {
[self refreshTableView];
}
}
I tried to refresh the tableview but that doesn't make it portrait again ...
this could be from the view hierachy ...
NavigationController->tableView (only portrait)->tableview->landscapeViewModalController
With iOS 6, you need to implement the following:
- (BOOL)shouldAutoRotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAll;
}
In your AppDelegate, you need to change the following:
[self.window addSubview:viewController.view];
to
[self.window setRootViewController:viewController];
Also, keep your current code if you want to support previous versions of iOS.
Use the following in appdelegate.
[self.window addsubview:viewcontroller];
This alone will solve your orientation problem.

setStatusBarOrientation issue

I have a navigation controller app. And first I push FirstViewController (support Portrait orientation) and then SecondViewController (supports all orientations). When I'm in landscape mode of SecondViewController and press back button, FirstViewController appears in landscape mode. That's why I manually rotate the navigation view, but when I want to set setStatusBarOrientation to Portrait (First view controller should appears only in portrait mode), the orientation of view controller is still landscape, and even if rotate the device to portrait mode, the orientation stay landscape
.Here is my code of FirstViewController:
- (void)viewWillAppear:(BOOL)animated
{
if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation))
{
if (self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
prevInterfaceOrientation = UIInterfaceOrientationLandscapeLeft;
self.navigationController.view.transform = CGAffineTransformIdentity;
self.navigationController.view.transform =
CGAffineTransformMakeRotation(degreesToRadians(90));
}
else if (self.interfaceOrientation ==
UIInterfaceOrientationLandscapeRight) {
prevInterfaceOrientation = UIInterfaceOrientationLandscapeRight;
self.navigationController.view.transform = CGAffineTransformIdentity;
self.navigationController.view.transform =
CGAffineTransformMakeRotation(degreesToRadians(-90));
}
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
[self.tableViewDetail reloadData];
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
if (toInterfaceOrientation == UIInterfaceOrientationPortrait)
{
if (prevInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
self.navigationController.view.transform = CGAffineTransformIdentity;
}
else if (prevInterfaceOrientation ==
UIInterfaceOrientationLandscapeRight) {
self.navigationController.view.transform = CGAffineTransformIdentity;
}
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait];
[self.tableViewDetail reloadData];
}
}
I even tried to use:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
if (UIInterfaceOrientationIsLandscape(prevInterfaceOrientation))
{
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait];
}
}
but self.interfaceOrientation still stays landscape, when I rotate to portrait.
But I really need to rotate the view to portrait mode manually to allow users to see,that FirstViewController suppors only portrait orientation.
I have the option to put the SecondViewController's view on MainWindow (like modal window), but I don't like this idea, because if apple has setStatusBarOrientation method, it seems to me, that it has to be right solve of this issue.
I would get rid of the transformations, and use
[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:animated];
This in combination with the forced redrawing of the view stack will get it done. This can be done by adding the following to viewDidAppear to the first controller (it doesn't work in viewWillApear).
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
if ([window.subviews count] > 0) {
UIView *view = [window.subviews objectAtIndex:0];
[view removeFromSuperview];
[window insertSubview:view atIndex:0];
}
else {
DLog(#"NO view to force rotate?");
}
Unfortunately, the transition animation is not very clean when you do this, so I would recommend taking a snapshot of the portrait screen, overlay this over your view, and then fade it out with a separate animation.
Steven Veltema's answer didn't work for me.
I had one view controller where all orientations where allowed, and the rest only supported portrait. When i had the first view controller in landscape and navigated to another view controller, the orientation didn't refresh as you are experiencing.
I found another trick to reload the views i correct orientation. Just add a modal view controller you don't even see it. Add this in all other views:
- (void)viewDidAppear:(BOOL)animated
{
UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
if(UIInterfaceOrientationIsLandscape(interfaceOrientation)){
UIViewController * viewController = [[UIViewController alloc] init];
[self presentModalViewController:viewController animated:NO];
[viewController dismissModalViewControllerAnimated:NO];
}
[super viewDidAppear:animated];
....
}
Another quick solution is
Click on your project in the left side bar.
In General settings, choose "Hide during application launch" option.

Reverting to portrait after Done pressed on movie player?

I've got a MPMoviePlayer working. It is designed to show a postage-stamp size movie as a subview in the view. When the phone is rotated into landscape, it goes into full screen mode. And when the phone is in portrait it goes into postage-stamp portrait mode.
The only problem is when I press Done when in landscape mode, it stays in landscape, with the postage stamp sized movie, rather than kick back into portrait..
Here's some of my code:
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
if (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight || toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) {
[moviePlayerController setFullscreen:YES animated:YES];
} else
{
[moviePlayerController setFullscreen:NO animated:YES];
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return interfaceOrientation == UIInterfaceOrientationLandscapeRight || interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationLandscapeLeft;
}
How would I get it to kick into portrait mode after pressing Done?
#cannyboy...you just need to use below method in your APPDelegate.m if your application only works with portrait mode
- (NSUInteger) application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
if ([[window.rootViewController presentedViewController] isKindOfClass:[MPMoviePlayerViewController class]])
{
//NSLog(#"in if part");
return UIInterfaceOrientationMaskAllButUpsideDown;
}
else
{
//NSLog(#"in else part");
return UIInterfaceOrientationMaskPortrait;
}}
I was the same problem and now I am telling you how I solved it. I don't know the below method is right or wrong but it work fine.
Instead of opening MPMoviePlayer in view open it in a new viewController. I mean create a new UIViewController to show the movie and push it some how so that user will not understood that they are redirecting into a new screen.
Disable the parent screen for landscape mode and allow MovieViewController to landscape.
When user press the done button or close button simply pop the viewController and as the previous screen don't support landscape mode so the screen will automatically shows in portrait mode.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(_moviePlayerWillExitFullscreen:)
name:MPMoviePlayerWillExitFullscreenNotification object:nil];
- (void)_moviePlayerWillExitFullscreen:(NSNotification *)notification
{
CGFloat ios = [[[UIDevice currentDevice] systemVersion] floatValue];
CGFloat min = 5.0;
if (ios >= min)
{
if (self.interfaceOrientation != UIInterfaceOrientationPortrait)
{
if([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortrait])
{
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait];
[self willRotateToInterfaceOrientation:self.interfaceOrientation duration:0];
[UIViewController attemptRotationToDeviceOrientation];
}
}
}
}
Note that this only works in ios 5.0 and later, and you will get a warning that setOrientation is not supported, but it works pretty well
One way you could try is to force your device to think it is in portrait mode. To do this, try using:
[[UIDevice currentDevice] setOrientation:UIDeviceOrientationPortrait];
If you do not want your device to show landscape while not playing a movie, you will also have to add some logic to your code that you have shown above to only change to landscape if the movie is playing.

UIViewController gets stuck in horizontal orientation after portrait rotation

View Controller A displays View Controller B in horizontal orientation
#pragma mark Rotation Delegate Methods
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations.
return YES;
}
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) {
[landscapeChartViewController.chartImageView reloadWithUrl:
[NSString stringWithFormat:#"someurl",[symbol uppercaseString]]];
NSLog(#"showing chart");
[self presentModalViewController:landscapeChartViewController animated:NO];
}
}
This works fine. View Controller B shows up in landscape orientation. Here is View Controller B's implementation:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) {
NSLog(#"dismissing chart");
[self.parentViewController dismissModalViewControllerAnimated:NO];
}
}
The problem is, when I go back into portrait orientation to show View Controller A, View Controller A is stuck in landscape orientation. How can I fix this?
EDIT: after reading your comment, I suggest trying to use willRotateToInterfaceOrientation:duration: instead of willAnimateRotationToInterfaceOrientation, like this:
controller A:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
if (UIInterfaceOrientationIsLandscape(toInterfaceOrientation)) {
[landscapeChartViewController.chartImageView reloadWithUrl:
[NSString stringWithFormat:#"someurl",[symbol uppercaseString]]];
NSLog(#"showing chart");
[self presentModalViewController:landscapeChartViewController animated:NO];
}
}
controller B:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) {
NSLog(#"dismissing chart");
[self.parentViewController dismissModalViewControllerAnimated:NO];
}
}
I do more or less the same in a project of mine, only between two non modal views.
One option is to move your code from willAnimateRotationToInterfaceOrientation: to didRotateFromInterfaceOrientation: and use self.interfaceOrientation in place of toInterfaceOrientation.
View Controller B shows up in landscape orientation. Here is View Controller B's implementation:
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
if (UIInterfaceOrientationIsPortrait(toInterfaceOrientation)) {
NSLog(#"dismissing chart");
[self dismissModalViewControllerAnimated:NO];
}
}
Did you implement the function willRotateToInterfaceOrientation? Also try using the Notification centre to notify the parent view controller that your modal view controller is rotated and then simply [self dismissModalViewControllerAnimated:YES]
I always write my orientation logic in didRotateFromInterfaceOrientation.
Here is a part of my code it works fine....
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
[connectCoverLockUnlockSwitch setFrame:CGRectMake(250,6,51,31)];
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight){
[connectCoverLockUnlockSwitch setFrame:CGRectMake(400,6,51,31)];
[self.tableView reloadData];
}
else if (orientation == UIDeviceOrientationPortraitUpsideDown || orientation == UIDeviceOrientationPortrait){
[connectCoverLockUnlockSwitch setFrame:CGRectMake(250,6,51,31)];
}
}
else if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation == UIDeviceOrientationUnknown || orientation == UIDeviceOrientationFaceUp) {
//return;
}
if (orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight) {
[connectCoverLockUnlockSwitch setFrame:CGRectMake(570,6,51,31)];
[self.tableView reloadData];
}
else if (orientation == UIDeviceOrientationPortraitUpsideDown || orientation == UIDeviceOrientationPortrait)
{
[connectCoverLockUnlockSwitch setFrame:CGRectMake(330,6,51,31)];
[self.tableView reloadData];
}
}

present modal view on rotate

So I have a UITableViewControler displaying a tableview in portrait mode.
As soon as i rotate the iPhone i want to present a modal view in landscape mode.
In the tableView i use:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
And to handle the present the modal view:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation) interfaceOrientation duration:(NSTimeInterval)duration {
if((interfaceOrientation == UIInterfaceOrientationLandscapeRight) || (interfaceOrientation == UIInterfaceOrientationLandscapeLeft))
{
NSLog(#"Push page view");
PagingViewController *s = [[PagingViewController alloc] initWithNibName:#"PagingView" bundle:nil];
s.hidesBottomBarWhenPushed = YES;
[self presentModalViewController:s animated:YES];
[s release];
}
}
The modal view i have the following:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
And to dismiss the modal view it self, I do:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation) interfaceOrientation duration:(NSTimeInterval)duration {
if (interfaceOrientation == UIInterfaceOrientationPortrait)
{
NSLog(#"Dismiss my self");
[self.parentViewController dismissModalViewControllerAnimated:YES];
}
}
Some how this works two times.
The third time i rotate the iPhone from Portrait mode to Landscape mode, i get a bad access error.
I cant figure out what gives me the error.
Anyone care for a shot?
The simplest way I can think of is to implement -shouldAutorotate... and dismiss the modal view and return NO to abort rotation. Perhaps that will be sufficient to avoid any concurrency issues. If this suggestion isn't to your liking take a look at NSNotificationCenter.