Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inaccurate device orientation returned by UIDeviceOrientationDidChangeNotification

Tags:

iphone

I'm listening to the UIDeviceOrientationDidChangeNotification in order to adjust my UI based on the device's orientation.

The problem is that the device orientation I'm getting from the notification seems inaccurate. If I start with the phone in portrait orientation and vertical (as if taking a picture with it) the orientation I get from the notification is correct. As the tilt of the phone approaches horizontal (as in laying flat on a table top) the orientation switches to landscape. This happens much before the phone is actually flat on the table. And this is without rotating the phone towards landscape at all. Is as if it had a preference for landscape.

When using other apps, like mail, I don't see this same behavior. It seems that mail only switches orientation once it's really sure you've gone to the new orientation.

Any help greatly appreciated.

Thanks,

like image 663
eddy Avatar asked Dec 13 '22 20:12

eddy


2 Answers

I found my problem.

In viewWillAppear I have:

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(didChangeOrientation:) name: UIDeviceOrientationDidChangeNotification object: 
     [UIDevice currentDevice]];

And here is the notification handler:

- (void) didChangeOrientation: (id)object {
    UIInterfaceOrientation interfaceOrientation = [[object object] orientation];
    //DLog(@"val is %i", interfaceOrientation);
    if (interfaceOrientation == UIDeviceOrientationLandscapeLeft || interfaceOrientation == UIDeviceOrientationLandscapeRight || interfaceOrientation == UIDeviceOrientationPortrait) {
    [self orientInterface:interfaceOrientation];
}

By checking that the orientation is one of the two landscapes or the two portraits I'm ignoring the UIDeviceOrientationFaceUp and UIDeviceOrientationFaceDown orientations. That way setting the phone in one of this two orientations won't have an effect on my interface's orientation.

My problem was that I was no considering the faceUp and faceDown and was handling them both in an else statement which was assuming landscape.

like image 54
eddy Avatar answered May 22 '23 03:05

eddy


If your only interest is your interface orientation (ie landscape or portrait orientation of the device), you should NOT use UIDevice:orientation (or the UIDeviceOrientation* constants if you will), but rather use the UIApplication:statusBarOrientation, which uses the UIInterfaceOrientation* constants.

I use the following code to check for landscape modus:

static inline bool isOrientationIsLandscape() {
    return UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]);
}

And for portrait modus:

static inline bool isOrientationIsPortrait() {
    return UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation]);
}

This cost me a whole morning to figure out, because there is no UIDeviceOrientationFace[Up|Down] on the simulator, only on the real device. So my app worked on the simulator all the time, but on the actual device I had some undefined behavoir during testing every now and then.

Now it works on the actual device like it does on the simulator.

HTH

like image 33
daniel Avatar answered May 22 '23 05:05

daniel