I had the same problem in my iPhone app, with an UIActionSheet
to ask the user if they wanted to take a photo, or pick an image from their gallery.
Prior to iOS 9, the following code worked fine:
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:nil
delegate:self
cancelButtonTitle:@"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:@"Take photo", @"Choose Existing", nil];
[actionSheet showInView:self.view];
However, in iOS 9, all this does is completely darken the screen, and nothing would appear.
Yeah... thanks Apple.
The solution is to replace the UIActionSheet
with a UIAlertController
.
UIAlertController* alert = [UIAlertController
alertControllerWithTitle:nil // Must be "nil", otherwise a blank title area will appear above our two buttons
message:nil
preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction* button0 = [UIAlertAction
actionWithTitle:@"Cancel"
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * action)
{
// UIAlertController will automatically dismiss the view
}];
UIAlertAction* button1 = [UIAlertAction
actionWithTitle:@"Take photo"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
// The user tapped on "Take a photo"
UIImagePickerController *imagePickerController= [[UIImagePickerController alloc] init];
imagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
imagePickerController.delegate = self;
[self presentViewController:imagePickerController animated:YES completion:^{}];
}];
UIAlertAction* button2 = [UIAlertAction
actionWithTitle:@"Choose Existing"
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action)
{
// The user tapped on "Choose existing"
UIImagePickerController *imagePickerController= [[UIImagePickerController alloc] init];
imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
imagePickerController.delegate = self;
[self presentViewController:imagePickerController animated:YES completion:^{}];
}];
[alert addAction:button0];
[alert addAction:button1];
[alert addAction:button2];
[self presentViewController:alert animated:YES completion:nil];
Notice that if you don't include a cancel option (an option with the UIAlertActionStyleCancel
style), then the action sheet will appear, but tapping anywhere outside of the action sheet won't dismiss the menu.
One gotcha:
Even though we've specified that we want this UIAlertController
to have the style UIAlertControllerStyleActionSheet
, you need to set the title as nil
, rather than a blank string, otherwise you get an ugly gap at the top of the window.
I can't wait to see what perfectly-working code iOS 9.2 will break...
Update
My comment: "However, in iOS 9, all this does is completely darken the screen, and nothing would appear" was slightly wrong.
Actually, I was opening my UIActionSheet
while the onscreen keyboard was visible. And in iOS 9, the keyboard will appear on top of your UIActionSheet
, so you can no longer see your action sheet (!!), but you do see that the rest of the screen has turned darker.
With UIAlertController
, iOS is slightly more user-friendly, as it hides the onscreen keyboard before attempting to display the action sheet at the bottom of the screen. Exactly why Apple doesn't do the same with UIActionSheets
is beyond me.
(Sigh.)
Please may I go back to using Visual Studio, now..?
Another update
Apple has said that UIActionSheets are now "deprecated in iOS 8".
However, if you want to keep using them, on your iOS screens which contain textboxes, then a workaround to this bug, errr, problem, is to add one line of code before displaying your UIActionSheet
:
[self.view endEditing:true];
This makes sure the onscreen keyboard is dismissed before displaying your "deprecated" action sheet..
(Sigh.) If anyone needs me, I'll be in the pub.