Sometimes, however, a user
should be prompted to make a decision based on the result of an action.
For example, if an application provides the option to share information
with a friend, the user might be prompted for the method of sharing
(such as sending an email, uploading a file, and so on). You can see
this behavior when adding a bookmark in Safari, as shown in Figure 1. This interface element is called an action sheet
and is an instance of UIActionSheet.
Action sheets are also used to
confirm actions that are potentially destructive to data. In fact, they
provide a separate bright-red button style to help draw a user’s
attention to potential deletion of data.
Displaying an Action
Sheet
Action sheets are very
similar to alerts in how they are initialized, modified, and,
ultimately, acted upon. However, unlike alerts, an action sheet can be
associated with a given view, tab bar, or toolbar. When an action sheet
appears onscreen, it is animated to show its relationship to one of
these elements.
To
create your first action sheet, we’ll use the method stub doActionSheet created within the
GettingAttentionViewController.m file. Recall that this method will be
triggered by pushing the Lights, Camera, Action Sheet button. Add the
code in Listing
1 to the doActionSheet method.
Listing
1.
1: - (IBAction)doActionSheet:(id)sender { 2: UIActionSheet *actionSheet; 3: actionSheet=[[UIActionSheet alloc] initWithTitle:@"Available Actions" 4: delegate:nil 5: cancelButtonTitle:@"Cancel" 6: destructiveButtonTitle:@"Destroy" 7: otherButtonTitles:@"Negotiate",@"Compromise",nil]; 8: [actionSheet showInView:self.view]; 9: }
|
Lines 2–3 declare and
instantiate an instance of UIActionSheet called actionSheet. Similar to the setup of an alert, the initialization
convenience method takes care of nearly all the setup. The parameters
are as follows:
initWithTitle:
Initializes the sheet with the specified title string.
delegate: Contains the object that will serve as the
delegate to the sheet. If this is set to nil
(which we will do initially), the sheet will be displayed, but pressing
a button will have no effect beyond dismissing the sheet.
cancelButtonTitle:
Set the string shown in the
default button for the alert.
destructiveButtonTitle: The title of the option that will result in information
being lost. This button will be presented in bright red (a sharp
contrast to the rest of the choices). If set to nil, no destructive button will be displayed.
otherButtonTitles: Adds additional buttons to the sheet. In this
example, we have a total of four buttons: the Cancel button, Destroy
button, and two other buttons.
In line 8, the action sheet
is displayed in the current view controller’s view (self.view) using
the UIActionSheet showInView: method. Figure 2 shows the result.
By
the Way
Action sheets can take up to
seven buttons (including Cancel and the Destroy button) while
maintaining the standard layout. If you exceed seven, however, the
display will automatically change into a scrolling table. This gives you
room to add as many options as you need.
Changing the Action
Sheet Appearance
Based on what you’ve learned so
far, you might have noticed that an action sheet is more configurable
than an alert view. An action sheet defines three different types of buttons with three different appearances (cancel,
destructive, other). Any of the button titles can be set to nil, and that button type will not be displayed in the
sheet.
By
the Way
To add buttons to the action
sheet outside of the initialization method, use the addButtonWithTitle:
method.
You can also change how the
sheet is drawn on the screen. In the example we’re creating, the showInView: method is used to animate the opening of the
sheet from the current view controller’s view. If you had an instance of
a toolbar or a tab bar, you could use showFromToolbar: or showFromTabBar: to make the sheet appear to open from either of
these user interface elements.
Perhaps more
dramatically, an action sheet can take on different appearances if you
set the actionSheetStyle property. For
example, try adding the following line to the doActionSheet
method:
actionSheet.actionSheetStyle=UIBarStyleBlackTranslucent;
This code draws the action
sheet in a translucent black style. You can also use UIActionSheetStyleAutomatic to inherit the style of the view’s toolbar (if any
is set) or UIActionSheetStyleBlackOpaque for a shiny
solid-black style.
Responding to an Action
Sheet Button Press
As you’ve seen, there
are more than a few similarities in how alert views and action sheets
are set up. The similarities continue with how an action sheets reacts
to a button press, for which we will follow almost the same steps as we
did with an alert view.
First, we need to conform to a
new protocol. Modify GettingAttentionViewController.h to include the UIActionSheetDelegate
protocol:
@interface GettingAttentionViewController :
UIViewController <UIAlertViewDelegate, UIActionSheetDelegate> {
IBOutlet UILabel *userOutput;
}
Next, to capture the click
event, we need to implement the actionSheet:clickedButtonAtIndex
method. As with alertView:clickedButtonAtIndex:, this method provides the button index that was pressed
within the action sheet. Add the code in Listing 2 to
GettingAttentionViewController.m.
Listing 2.
1: - (void)actionSheet:(UIActionSheet *)actionSheet 2: clickedButtonAtIndex:(NSInteger)buttonIndex { 3: NSString *buttonTitle=[actionSheet buttonTitleAtIndex:buttonIndex]; 4: if ([buttonTitle isEqualToString:@"Destroy"]) { 5: userOutput.text=@"Clicked 'Destroy'"; 6: } else if ([buttonTitle isEqualToString:@"Negotiate"]) { 7: userOutput.text=@"Clicked 'Negotiate'"; 8: } else if ([buttonTitle isEqualToString:@"Compromise"]) { 9: userOutput.text=@"Clicked 'Compromise'"; 10: } else { 11: userOutput.text=@"Clicked 'Cancel'"; 12: } 13: }
|
Now we can use buttonTitleAtIndex (line 3) to get the titles used for the buttons
based on the index provided. The rest of the code follows exactly the
same pattern created earlier. Lines 4–12 test for the different button
titles and update the view’s output message to indicate what was chosen.
An
Alternative Approach
Once again, we’ve chosen
to match button presses based on the title of the onscreen button. If
you’re adding buttons dynamically, however, this might not be the best
approach. The addButtonWithTitle method,
for example, adds a button and returns the index of the button that was
added. Similarly, the cancelButtonIndex and destructiveButtonIndex methods provide the indexes for the two
specialized action sheet buttons.
By checking against these
index values, you can write a version of the actionSheet:clickedButtonAtIndex: method that is not dependent on the title
strings. The approach you take in your own applications should be based
on what creates the most efficient and easy-to-maintain code.