Using UIActionSheet in landscape mode on iPhone

The UIActionSheet class of the iPhone OS can be used to present the user a modal view with a descriptive text and some buttons the user can choose from. This class is usually used when the user has to confirm a certain action (like deleting something) or as some kind of contextual menu (for example when you tap for a longer time on a link in Safari or iCab Mobile). A UIActionSheet object would look like this:

But there is a problem: the screen area of the small iPhone screen is limited and only a limited number of buttons will fit on the screen. In portrait mode (like in the screenshot from above), about 6-7 buttons will fit on the screen, which is usually more than enough for most tasks. But in landscape mode the number of buttons can be an issue. Because of the reduced height of the screen in landscape mode, less buttons will fit on the screen. Under iPhone OS 2.x the top most buttons might be no longer accessible because they are located outside of the screen. Since iPhone OS 3.0, Apple has solved this issue by converting the buttons into a scrollable list, if the available space isn’t enough for all buttons.

Here’s how this looks like under iPhone OS 2.x:

Here’s how this looks linke under iPhone OS 3.x:

If you write an app which requires at least OS 3.0, you can just ignore this problem. But if your app should still support OS 2.x (especially iPod Touch users are slow in upgrading, because the OS 3.x update is not free for iPod Touch users), you have to take care about this problem.

Reducing the number of buttons in landscape mode is usually not an option, and moving half of the buttons into a second UIActionSheet object which will open when you click a button labeled “More options…” can be an easy solution, but it makes navigation through all the options less comfortable to the user.

A simple solution for this problem would be to open the UIActionSheet in portrait mode orientation under OS 2.x while the app itself remains in landscape mode. This way the user would always get the full list of buttons, no special reduced button set for different orientations would be needed, and also no need to introduce multi UIActionSheet objects which are linked together with some buttons.

This can look like this in iPhone OS 2.x (Note: in the background you can see that the app is still in landscape mode):

How can this be done? When you open a UIActionSheet, you can do the following:

  UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:@"Some text..."
                           delegate:self
                  cancelButtonTitle:@"Cancel"
             destructiveButtonTitle:@"Delete"
                  otherButtonTitles:@"Button 1",@"Button 2",nil];

  if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 3.0 ||
      UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation])) {
    [sheet showInView:self.view];
  } else {
    [sheet showInView:self.view.window];
  }
  [sheet release];

This code fragment will first create the UIActionSheet object (as usual). Then we check if we’re running under OS 3.x or newer, or if the current orientation is the portrait mode. If this is the case we just show the UIActionSheet within the view of the current view controller (this is what we would have done normally). But when running under OS 2.x and the device is currently in landscape mode, we do not show the UIActionSheet in the current view, but instead it is shown in the window object (which is also a subclass of UIView). Unlike the normal “UIView” objects where the coordinate system will be automatically transformed according to the current device orientation so that the top left corner will have the coordinate (0,0), the coordinate system of the window object (the root object of the view hierarchy) won’t be transformed. It will always remain the same and is based on the standard portrait orientation. So when we open the UIActionSheet here, it will be shown as if the device would be in portrait mode.

This way we can use UIActionSheets with more than 3-4 buttons in landscape mode safely under OS 3.x and also under OS 2.x without risking that some buttons are no longer accessible.

Here you can download an archive of an example project which demonstrates this technique: ActionSheetTest.zip (12 KB)

Let the example app run under OS 2.x and tap on the two buttons of the main view to find out how the UIActionSheet will look like in landscape and portrait mode with and without the technique described above. Also compare this when running the app under OS 3.x.