Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Action Sheet problems in iOS 9

Apple has deprecated the action sheet in iOS 8.3 how do you add an action sheet to my user interface?

I realized Apple's documentation isn't very clear on how to create an action sheet with UIAlertController. So after a little playing around I just wanted to share my code, since I couldn't really find anything useful on Stack Exchange about this topic.

like image 510
Derek Saunders Avatar asked Sep 28 '15 13:09

Derek Saunders


3 Answers

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.

enter image description here

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.

enter image description here

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.

like image 106
Mike Gledhill Avatar answered Oct 18 '22 00:10

Mike Gledhill


Here is a snippet of the code I used in my apps for an action sheet, just in case anyone needed help trying to figure out how to use UIAlertController as an Action Sheet.

UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Action Sheet"
                                                                       message:@"This is an action sheet."
                                                                preferredStyle:UIAlertControllerStyleActionSheet];

        UIAlertAction *button1 = [UIAlertAction actionWithTitle:@"Button Title 1" style:UIAlertActionStyleDefault
                                                            handler:^(UIAlertAction * action) {
                                                                //code to run once button is pressed
                                                            }];
        UIAlertAction *button2 = [UIAlertAction actionWithTitle:@"Button Title 2" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
            //code to run once button is pressed
        }];

        [alert addAction:button1];
        [alert addAction:button2];
        [self presentViewController:alert animated:YES completion:nil];
like image 34
Derek Saunders Avatar answered Oct 17 '22 23:10

Derek Saunders


In iOS 9 and for iPad I had to add some important changes. May be someone in future might need this.

    UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Server"
                                                                   message:@"Choose server to point to"
                                                            preferredStyle:UIAlertControllerStyleActionSheet];
    UIAlertAction *button1 = [UIAlertAction actionWithTitle:@"Development" style:UIAlertActionStyleDefault
                                                    handler:^(UIAlertAction * action) {
                                                        //code to run once button is pressed
                                                    }];
    UIAlertAction *button2 = [UIAlertAction actionWithTitle:@"Production" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
        //code to run once button is pressed
    }];
    [alert addAction:button1];
    [alert addAction:button2];
    UIPopoverPresentationController *popPresenter = [alert popoverPresentationController];
    popPresenter.sourceView = self.view;
    //To present the actionsheet the bottom of screen
    popPresenter.sourceRect = CGRectMake(self.createBtn.frame.origin.x, self.view.frame.size.height, self.createBtn.frame.size.width, self.createBtn.frame.size.height);
    alert.modalPresentationStyle = UIModalPresentationPopover;
    [self presentViewController:alert animated:YES completion:nil];
like image 41
PrafulD Avatar answered Oct 17 '22 23:10

PrafulD