Avatar of marc

by

Handling UIDeviceOrientationFaceUp & UIDeviceOrientationFaceDown

June 29, 2010 in Cocoa, short, Xcode

If your iPad (or iPhone) application uses UIDeviceOrientationDidChangeNotification to detect device rotation, there might be a couple cases you forget to think about. If your device is lying down flat (or upside down), there is still an implied “felt” orientation, based on how the iPad was last held before it went flat. How will iOS let you know about this? Here is what i found out when writing Dwarfland Photos:

After you sign up for UIDeviceOrientationDidChangeNotification, if your device is flat, you will receive 3 notifications. The first one will be with a value if UIDeviceOrientationFaceUp (or UIDeviceOrientationFaceDown), matching the actual current physical location of the device. Right afterwards, you get another notification, and this one will specify one of UIDeviceOrientationPortraitUIDeviceOrientationPortraitUpsideDown,  UIDeviceOrientationLandscapeLeft,  or UIDeviceOrientationLandscapeRight – depending on what the UI was showing before your app started (and indicating how the user will think of the device as being rotated). This is followed right up with a third notification that brings you back to either UIDeviceOrientationFaceUp or UIDeviceOrientationFaceDown.

Essentially, the device is pretending the user really quickly shook it back to an upright position, and back down.

The best way to handle this that i found in my app was to never ever use the actual reported orientation do fo any drawing or calculation, but instead cache the last “felt” orientation, within an handler as follows:

- (void)orientationChanged:(NSNotification *)notification
{
  UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation];
  if (orientation == UIDeviceOrientationPortrait ||
      orientation == UIDeviceOrientationPortraitUpsideDown ||
      orientation == UIDeviceOrientationLandscapeLeft ||
      orientation == UIDeviceOrientationLandscapeRight)
  {
    if (!currentOrientation)
    {
      currentOrientation = orientation;
      [self prepareScreen];
    }
    currentOrientation = orientation;
  }
  [[UIApplication sharedApplication] setStatusBarOrientation:currentOrientation animated:YES];
}

All my code will use currentOrientation, so it will always have a proper orientation value. Also any screen initialization that depends on having a proper orientation (in Dwarfland Photos that is the initial drawing of the startup logo, once Default.png disappears)  i do in prepareScreen, which is not called until i obtained the proper “felt” rotation.

Comments are closed.