UIDeviceOrientationFaceUp - how to distinguish between portrait and landscape? - iphone

I'm trying to find out if the device is in portrait or landscape mode. My code works quite well if the device is not facing up. If it does face up (and orientation == 5), it won't distinguish between portrait and landscape. Is there anyway to determine the "orientation" in terms of landscape / portrait if the UIDeviceOrientation is FaceUp?
My code:
UIDeviceOrientation interfaceOrientation = [[UIDevice currentDevice] orientation];
NSLog(#"orientation: %d", interfaceOrientation);
if (interfaceOrientation == UIDeviceOrientationIsLandscape(interfaceOrientation)) {
NSLog(#"LANDSCAPE!!!");
}
if (interfaceOrientation == UIDeviceOrientationIsPortrait(interfaceOrientation)) {
NSLog(#"PORTRAIT!!!");
}

You should not confuse UIDeviceOrientation and UIInterfaceOrientation, they are different but related as shown by their declaration
typedef enum {
UIDeviceOrientationUnknown,
UIDeviceOrientationPortrait,
UIDeviceOrientationPortraitUpsideDown,
UIDeviceOrientationLandscapeLeft,
UIDeviceOrientationLandscapeRight,
UIDeviceOrientationFaceUp,
UIDeviceOrientationFaceDown
} UIDeviceOrientation;
typedef enum {
UIInterfaceOrientationPortrait = UIDeviceOrientationPortrait,
UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,
UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft
} UIInterfaceOrientation;
UIDeviceOrientation tells you what the orientation of the device is. UIInterfaceOrientation tells you what the orientation of your interface is, and is used by UIViewController. UIInterfaceOrientation will clearly be either portrait or landscape, whereas UIDeviceOrientation can have ambiguous values (UIDeviceOrientationFaceUp, UIDeviceOrientationFaceDown, UIDeviceOrientationUnknown).
In any case you should not attempt to determine the orientation of a UIViewController with [[UIDevice currentDevice] orientation], as no matter what the device orientation is the UIViewController interfaceOrientation property can be different (for example if your app does not rotate to landscape at all [[UIDevice currentDevice] orientation] can be UIDeviceOrientationLandscapeLeft while viewController.interfaceOrientation can be UIInterfaceOrientationPortrait).
Update:
As of iOS 8.0, [UIViewController interfaceOrientation] is deprecated. An alternative offered here is [[UIApplication sharedApplication] statusBarOrientation]. This also returns UIInterfaceOrientation.

I make this code skeleton for dealing with wanted & unwanted devices orientations, in my case i want to ignore the UIDeviceOrientationUnknown, UIDeviceOrientationFaceUp and UIDeviceOrientationFaceDown, caching the last allowed orientation. This code deals with iPhone and iPad devices and can be useful for you.
- (void)modXibFromRotation {
UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
NSString *device = [[UIDevice currentDevice]localizedModel];
UIInterfaceOrientation cachedOrientation = [self interfaceOrientation];
if ([device isEqualToString:#"iPad"]) {
if (orientation == UIDeviceOrientationUnknown ||
orientation == UIDeviceOrientationFaceUp ||
orientation == UIDeviceOrientationFaceDown) {
orientation = (UIDeviceOrientation)cachedOrientation;
}
if (orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight) {
/* Your code */
}
if (orientation == UIDeviceOrientationPortrait || orientation == UIDeviceOrientationPortraitUpsideDown) {
/* Your code */
}
}
if ([device isEqualToString:#"iPhone"] || [device isEqualToString:#"iPod"]) {
if (orientation == UIDeviceOrientationUnknown ||
orientation == UIDeviceOrientationFaceUp ||
orientation == UIDeviceOrientationFaceDown) {
orientation = (UIDeviceOrientation)cachedOrientation;
}
if (orientation == UIDeviceOrientationLandscapeLeft || orientation == UIDeviceOrientationLandscapeRight) {
/* Your code */
}
if (orientation == UIDeviceOrientationPortrait || orientation == UIDeviceOrientationPortraitUpsideDown) {
/* Your code */
}
}
}

As of iOS13 use
UIInterfaceOrientation orientation;
if (#available(iOS 13.0, *)) {
orientation = self.window.windowScene.interfaceOrientation;
} else {
orientation = [[UIApplication sharedApplication] statusBarOrientation];
}

Related

how to know the device orientation correctly

I want to know the device orientation when user start my app , in order to produce different view. What I find strange is as below:
- (void)viewDidLoad
{
if ([UIDevice currentDevice].orientation == UIDeviceOrientationPortrait) {
NSLog(#"1");
}
if ([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeRight) {
NSLog(#"2");
}
if ([UIDevice currentDevice].orientation == UIDeviceOrientationLandscapeLeft) {
NSLog(#"3");
}
if ([UIDevice currentDevice].orientation == UIDeviceOrientationPortraitUpsideDown) {
NSLog(#"4");
}
}
No one is printed! I did it on the ipad simulator and I think the orientation should be UIDeviceOrientationPortrait. Why this happen? and how to know the orientation correctly?
Try to use
[UIApplication sharedApplication].statusBarOrientation
instead of
[UIDevice currentDevice].orientation
It may be the case that the simulator simply cannot be in an orientation state (it makes no sense, as you can't really rotate your computer...) Have you checked whether it returns UIDeviceOrientationUnknown?
The documentation or UIDevice states:
You get the current orientation using the orientation property or
receive change notifications by registering for the
UIDeviceOrientationDidChangeNotification notification. Before using
either of these techniques to get orientation data, you must enable
data delivery using the beginGeneratingDeviceOrientationNotifications
method
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIDevice_Class/Reference/UIDevice.html
So it is probably that you get Unkown orientation because you never started the orientation notifications generation.
You should also log the value in your viewDidLoad to confirm exactly what you receive when you get the orientation. That would be a good starting point for further investigation.
Use this :-
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
if(interfaceOrientation == UIInterfaceOrientationPortrait || interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown)
{
//code for portrait
}
else
{ //code for Landscape
}
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight || interfaceOrientation == UIInterfaceOrientationPortrait ||interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown);
}
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation is the delegate method oa uiviewcontroller.
According to the docs, the orientation property of UIDevice will always return 0 (i.e., UIDeviceOrientationUnknown) unless -beginGeneratingDeviceOrientationNotifications has been called first. This method will enable the accelerometer, deliver notification changes, and update the orientation property of the UIDevice singleton.

landscape... iPhone... accelerometer issue

there is all this....
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation {
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return (interfaceOrientation != UIInterfaceOrientationPortrait && interfaceOrientation != UIInterfaceOrientationLandscapeLeft && interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
} else {
return YES;
}
}
and i want the accelerometer to work in landscape as if it was in portrait... I have all the accelerometer stuff such as:
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration*)acceleration {
accx = acceleration.x;
}
also i have tried looking at other questions but i can't find the solution...?
Ok, if understood correctly, you are in portrait (in the X axis direction see the image), tilt right and tilt left then the image in your app should move right and left. Then you switch to landscape and your image should now move right and left but it doesn't, the axis you should pay attention now is the Y axis.
There is no reason why you should not be seeing any change in the Y axis when you rotate to landscape, unless there is hardware damage and that the accelerometer had stopped working.
Now, what you ask for is a way to reset the accelerometer so that you can keep reading from the X even though the changes are happening in the Y axis? No, there is no way to do this, unless you write an extra method ... something along the lines of:
+(UIAccelerationValue)fixedAccelerationValue{
//Check which axis you should look for
if ( [[UIDevice currentDevice] orientation] == UIInterfaceOrientationPortrait || [[UIDevice currentDevice] orientation] == UIInterfaceOrientationUpsideDown ){
//read from the x axis
}
else{
//read from the y axis
}
}
I had the same problem and fixed it by adding the BOOL statement prior to the UIACCELEROMETER in the implementation file.
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation == UIInterfaceOrientationPortrait ||
interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
interfaceOrientation == UIInterfaceOrientationLandscapeRight)
return YES;
else
return NO;
}
Hope this helps.

UIInterfaceOrientation bug?

In my iPhone app I need to detect the current orientation and I have to determine if I'm in portrait or landscape. I use this code:
UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) {
NSLog(#"portrait");
...
} else {
NSLog(#"landscape");
...
}
Everything is ok when my iPhone is in my hand.
But when i put it on the table and i run the application, the content is displayed on the screen in portrait mode and my code goes to else and NSLog prints landscape.
Is my test incomplete ? How to prevent this case ?
EDIT : the test is performed in my controller viewDidLoad method and my application handle rotation.
UIDevice.orientation is of type UIDeviceOrientation, which is a superset of UIInterfaceOrientation. You are probably getting the value UIDeviceOrientationFaceUp.
This underscores that yes, your test is incomplete. You should write something like this:
UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation];
if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) {
NSLog(#"portrait");
...
} else if (orientation == UIInterfaceOrientationLandscapeLeft || orientation == UIInterfaceOrientationLandscapeRight) {
NSLog(#"landscape");
...
} else {
NSLog(#"WTF? %d", orientation);
assert(false);
}
Then, you'll know if you if you've missed something.
UIDevice.orientation can return that the device is flat or upside down (not inverted portrait, upside-down as in laying on its face). Instead call UIViewController.interfaceOrientation on your root view controller.
I would recommend using UIDeviceOrientationIsValidInterfaceOrientation(orientation)
It will tell you if its a valid orientation (valid being either landscape or portrait, not FaceUp/FaceDown/UnKnown). Then you can treat it as if its portrait if its unknown.
This is how I do it:
if (UIDeviceOrientationIsValidInterfaceOrientation(interfaceOrientation) && UIInterfaceOrientationIsLandscape(interfaceOrientation)) {
// handle landscape
} else {
// handle portrait
}

How can I query the current orientation of an iPhone/iPad screen?

I was curious to know if there is some way to determine the orientation of a screen on iPhone/iPad.
Currently I find myself setting a member variable when this message is called:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
self.orientation = interfaceOrientation;
return YES;
}
... which feels like something I should be able to query as a state instead of having to track it when it changes.
UIViewController has the interfaceOrientation property.
Don't get confused by orientation in UIDevice, which is not the orientation of the interface, but the physical orientation.
Use this if you have a status bar on top.
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown) {
// portrait
} else {
// landscape
}
You can do [[UIDevice currentDevice] orientation].

UIDevice Orientation

I have the following code in a method. When I run this in the simulator the debugger skips right over the code?? What am I missing?
if (([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeLeft) ||
([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeRight))
{
} else {
}
The best way to determine interface orientation is to look at status bar orientation:
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if(orientation == UIInterfaceOrientationPortrait ||
orientation == UIInterfaceOrientationPortraitUpsideDown) {
//Portrait orientation
}
if(orientation == UIInterfaceOrientationLandscapeRight ||
orientation == UIInterfaceOrientationLandscapeLeft) {
//Landscape orientation
}
UIDevice class measures orientation based on accelerometer and if device lays flat, it won't return the correct orientation.
Note that there's a macro UIDeviceOrientationIsLandscape and UIDeviceOrientationIsPortrait, so instead of comparing it separately to LandscapeLeft and LandscapeRight you could just do it like this:
if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation))
{
}
Update 2
This shouldn't matter, but try turning on orientation notifications:
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(detectOrientation) name:#"UIDeviceOrientationDidChangeNotification" object:nil];
Update
My bad, I assumed it was empty.
Try removing the or statement and just test for a single orientation. See if that fixes it. Maybe there is a bracket problem or something silly.
I have the following test working in production code, so your technique should work:
if (([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeLeft) ||
([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeRight)) {
}
Original Answer
You have to actually put statements in the if blocks to get it to step in.
The debugger is smart enough to skip over empty blocks.
Another way of doing this without turning on orientation notification would be to
Step 1: Save the current orientation in a local variable myCurrentOrientation and assign it like this:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration
{
myCurrentOrientation = toInterfaceOrientation;
}
Step 2: Use myCurrentOrientation for your check
if (UIInterfaceOrientationIsLandscape(myCurrentOrientation) == YES) {
// landscape
}
else {
// portrait.
}
Say you are inside a Springboard tweak and want to show something depending on the orientation of the current app, then you can use this (jailbreak only):
UIInterfaceOrientation o = [[UIApplication sharedApplication] _frontMostAppOrientation];
Heh you need to call [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]
before obtaining the value. Have a look at documentation of this method. Took me a while to track this down.
I recommend you to use my highlighted code instead of yours to safe some code of lines.
-(void) viewDidLoad
{
[super viewDidLoad];
[self rotations];
}
-(void)rotations
{
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(orientationChanged:)
name:UIDeviceOrientationDidChangeNotification
object:nil];
}
-(void) orientationChanged:(NSNotification *)notification
{
//USE THIS PART
//USE THIS PART
//USE THIS PART
//USE THIS PART
//USE THIS PART
if (UIDeviceOrientationIsPortrait([UIDevice currentDevice].orientation))
{
}
}
INSTEAD OF
if([[UIDevice currentDevice] orientation] == UIInterfaceOrientationPortrait ||
[[UIDevice currentDevice] orientation] == UIInterfaceOrientationPortraitUpsideDown)
{
}
Here is a method to find the orientation and the true center of the screen. I used Tuszy's method so I could set UIActivityIndicatorView properly.
- (BOOL) isPortraitOrientation {
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
if(orientation == UIInterfaceOrientationPortrait ||
orientation == UIInterfaceOrientationPortraitUpsideDown) {
return true;
}
if(orientation == UIInterfaceOrientationLandscapeRight ||
orientation == UIInterfaceOrientationLandscapeLeft) {
return false;
}
return false;
}
And the way to get center...
- (void) findMyUIViewCenter {
CGPoint myCenter;
if ([self isPortraitOrientation]) {
myCenter = self.view.center;
}
else {
myCenter = CGPointMake(self.view.frame.size.height / 2.0, self.view.frame.size.width / 2.0);
}
NSLog(#"true center -- x:%f y:%f )",myCenter.x,myCenter.y);
}