Reputation: 7416
I want to present a view that responds to orientation changes but for various reasons can't use iOS's built-in autorotation. In viewDidLoad
I use the current orientation to determine the initial layout of the view:
_originalOrientation = [UIDevice currentDevice].orientation;
// if we were launched flat or unknown, use the status bar orientation as a guide
if (_originalOrientation == UIDeviceOrientationUnknown ||
_originalOrientation == UIDeviceOrientationFaceDown ||
_originalOrientation == UIDeviceOrientationFaceUp) {
_originalOrientation = UIDeviceOrientationFromInterfaceOrientation([UIApplication sharedApplication].statusBarOrientation);
}
As you can see from my comment, I need to handle the case where [UIDevice currentDevice].orientation
is not a usable direction (i.e. the device is flat or in an unknown orientation). In this scenario, I attempt to use the statusBarOrientation
to infer the device's orientation (using UIViewController
's interfaceOrientation
would be an alternative way to get the same information):
UIDeviceOrientation UIDeviceOrientationFromInterfaceOrientation(UIInterfaceOrientation interface) {
// note: because UIInterfaceOrientationLandscapeLeft and UIInterfaceOrientationLandscapeRight have the same value, this conversion can't distinguish them
if (interface == UIInterfaceOrientationLandscapeLeft) {
return UIDeviceOrientationLandscapeLeft;
} else if (interface == UIInterfaceOrientationLandscapeRight) {
return UIDeviceOrientationLandscapeRight;
} else if (interface == UIInterfaceOrientationPortraitUpsideDown) {
return UIDeviceOrientationPortraitUpsideDown;
} else {
return UIDeviceOrientationPortrait;
}
}
However my logic can't accurately discern the two landscape cases because they are defined UIApplication.h
to be the same constant value:
// Note that UIInterfaceOrientationLandscapeLeft is equal to UIDeviceOrientationLandscapeRight (and vice versa).
// This is because rotating the device to the left requires rotating the content to the right.
typedef NS_ENUM(NSInteger, UIInterfaceOrientation) {
UIInterfaceOrientationPortrait = UIDeviceOrientationPortrait,
UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,
UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft
};
Is there an alternative way I can distinguish between UIInterfaceOrientationLandscapeLeft
and UIInterfaceOrientationLandscapeRight
? Is there a better way for me to perform my "fallback" logic besides using the status bar orientation?
Upvotes: 3
Views: 3387
Reputation: 1750
Had face the same issue. here is the answer, always go for UIIntefaceOrientation to check whether current orientation is Landscape or Portrait.
OBJECTIVE C :
if([[UIApplication sharedApplication] statusBarOrientation] == UIDeviceOrientationLandscapeLeft || [[UIApplication sharedApplication] statusBarOrientation] == UIDeviceOrientationLandscapeRight)
{
//Go Here for landscape
}
else if ([[UIApplication sharedApplication] statusBarOrientation] == UIDeviceOrientationPortrait || [[UIApplication sharedApplication] statusBarOrientation] == UIDeviceOrientationPortraitUpsideDown)
{
//Go Here for Portrait
}
SWIFT :
let currentOrient : UIInterfaceOrientation = UIApplication.shared.statusBarOrientation
if currentOrient == UIInterfaceOrientation.landscapeLeft || currentOrient == UIInterfaceOrientation.landscapeRight
{
//Go Here for landscape
}
else if currentOrient == UIInterfaceOrientation.portrait || currentOrient == UIInterfaceOrientation.portraitUpsideDown
{
//Go Here for Portrait
}
Upvotes: 0
Reputation: 351
This is how I have done it in the pass
Create a global variable called previousOr. Then in your first viewController use the following code to determine the status bar position. I put it in the viewDidAppear
if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) {
previousOr = [NSString stringWithFormat:@"L"];
}
else if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight) {
previousOr = [NSString stringWithFormat:@"L"];
}
else if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortrait) {
previousOr = [NSString stringWithFormat:@"P"];
}
else if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown) {
previousOr = [NSString stringWithFormat:@"P"];
}
Then in your subsequent viewControllers you have the following in the ViewDidLoad methods, this will detect if the device is portrait or landscape or if the device is flat what the device was in before they placed it flat:
if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation)) {
NSLog(@"landscape");
[self switchToLandscape];
}
else if (UIDeviceOrientationIsPortrait([UIDevice currentDevice].orientation)) {
NSLog(@"portrait");
[self switchToPortrait];
}
else {
if ([previousOr isEqualToString:@"L"]) {
[self switchToLandscape];
}
else {
[self switchToPortrait];
}
}
Then you also have the following to do the re-plotting of elements on the view
- (void)switchToLandscape {
previousOr = [NSString stringWithFormat:@"L"];
//do stuff like replot centers
}
- (void)switchToPortrait {
previousOr = [NSString stringWithFormat:@"P"];
//do stuff like replot centers
}
and then you also have the following to detect the change in orientation:
- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft) {
[self switchToLandscape];
}
else if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight) {
[self switchToLandscape];
}
else if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortrait) {
[self switchToPortrait];
}
else if ([UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown) {
[self switchToPortrait];
}
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
-(BOOL) shouldAutorotate {
return YES;
}
NOTE; I put in both shouldAutorotateToInterfaceOrientation and shouldAutoRotate for backward compatibility.
Upvotes: 0
Reputation: 10754
You wrote:
However my logic can't accurately discern the two landscape cases because they are defined UIApplication.h to be the same constant value
I am pretty sure that they are not! The values for interface and device orientations are swapped. See UIApplication.h
:
typedef NS_ENUM(NSInteger, UIInterfaceOrientation) {
UIInterfaceOrientationPortrait = UIDeviceOrientationPortrait,
UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,
UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft
};
The interface orientation UIInterfaceOrientationLandscapeLeft
is equal to the device orientation UIDeviceOrientationLandscapeRight
, and vice versa. But:
UIInterfaceOrientationLandscapeLeft != UIInterfaceOrientationLandscapeRight
UIDeviceOrientationLandscapeLeft != UIDeviceOrientationLandscapeRight
Try this code, I assume that will fix the problem:
UIDeviceOrientation UIDeviceOrientationFromInterfaceOrientation(UIInterfaceOrientation interface) {
// interface orientation left is device orientation right
if (interface == UIInterfaceOrientationLandscapeLeft) {
return UIDeviceOrientationLandscapeRight;
// interface orientation right is device orientation left
} else if (interface == UIInterfaceOrientationLandscapeRight) {
return UIDeviceOrientationLandscapeLeft;
} else if (interface == UIInterfaceOrientationPortraitUpsideDown) {
return UIDeviceOrientationPortraitUpsideDown;
} else {
return UIDeviceOrientationPortrait;
}
}
BTW, you should also consider to use an own prefix for your function instead of UI
, otherwise it may be easy to mistakenly assume that UIDeviceOrientationFromInterfaceOrientation
is an API function.
Upvotes: 4
Reputation: 1
You always can determine device orientation using gravity
property of CMDeviceMotion
class. Property return a normalized vector pointed to Earth center (aka real gravity vector). If you not interested in angles, you can test only signs and generate constants for your purpose.
Upvotes: 0
Reputation: 795
If you're showing what the camera is seeing, i would ignore all orientations and show the user a preview of what the devices sees in portrait. What they see will always be "correct", and never accidentally upside down.
Upvotes: 0
Reputation: 104092
The orientation property of UIDevice is an enum that does distinguish between landscape left and right (their values are 3 and 4 respectively), so you can check that value.
typedef enum {
UIDeviceOrientationUnknown,
UIDeviceOrientationPortrait,
UIDeviceOrientationPortraitUpsideDown,
UIDeviceOrientationLandscapeLeft,
UIDeviceOrientationLandscapeRight,
UIDeviceOrientationFaceUp,
UIDeviceOrientationFaceDown
} UIDeviceOrientation;
Upvotes: 3