110

I have an array of strings that I want to use for button titles on a UIActionSheet. Unfortunately, the otherButtonTitles: argument in the method invocation takes a variable length list of strings, not an array.

So how I can I pass these titles into the UIActionSheet? The workaround I've seen suggested is to pass nil into otherButtonTitles:, then specify the button titles individually by using addButtonWithTitle:. But this has the problem of moving the "Cancel" button to the first position on the UIActionSheet rather than the last; I want it to be the last one.

Is there a way to 1) pass an array in lieu of a variable list of strings, or alternatively 2) move the cancel button to the bottom of the UIActionSheet?

Thanks.

TheNeil
  • 1,985
  • 2
  • 17
  • 36
Greg Maletic
  • 6,205
  • 8
  • 51
  • 73
  • not sure if this will work but the cancelButtonIndex property of UIActionSheet is not read-only. Try setting it and see if that changes the order of the buttons? – lostInTransit Mar 05 '10 at 03:51

4 Answers4

249

I got this to work (you just need to, be ok with a regular button, and just add it after :

NSArray *array = @[@"1st Button",@"2nd Button",@"3rd Button",@"4th Button"];

    UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"Title Here"
                                                             delegate:self
                                                    cancelButtonTitle:nil
                                               destructiveButtonTitle:nil
                                                    otherButtonTitles:nil];

    // ObjC Fast Enumeration
    for (NSString *title in array) {
        [actionSheet addButtonWithTitle:title];
    }

    actionSheet.cancelButtonIndex = [actionSheet addButtonWithTitle:@"Cancel"];

    [actionSheet showInView:self.view];
mylogon
  • 2,283
  • 2
  • 24
  • 39
Jab
  • 21,612
  • 20
  • 66
  • 111
  • 19
    This works; thanks. Didn't realize that the cancelButtonIndex property could be set. One thing I think we can all agree on: Apple's API for this sucks. – Greg Maletic Mar 05 '10 at 19:14
  • 11
    I second this! And 99,99% of their documentation also sucks. It is like trying to learn brain surgery from a book written in archaic hebrew without knowing that language. – Duck Aug 16 '10 at 23:35
  • 4
    I very much wish I could up vote this many many more times. Cracking answer and I cannot believe I've gone this long not knowing about this! – mattjgalloway Apr 04 '12 at 08:56
  • What about if we want the cancel button to be red like usual? – user4951 Mar 12 '13 at 10:07
  • 1
    @JimThio `cancelButton` is not red. The `destructiveButton` is red. – Armin Jul 30 '13 at 04:02
  • 1
    Sadly, this solution suffers from a bug in UIActionSheet that `[UIActionSheet addButtonWithTitle]` does not seem to correctly set `firstOtherButtonIndex` (which should be used in the delegate's `actionSheet:clickedButtonAtIndex:` rather than hardcoding 0 or similar stuff). Getting nasty with converting an `NSArray` to `va_list` doesn't sound like a great solution either. :-( This API is so damn ugly. – Daniel Rinser Aug 29 '13 at 12:36
  • I used this recently showing the action sheet from a bar button item, and it seems to have a bug because the last item is not being shown. I had to add an empty button title to workaround this. I'm not sure if this is only on iOS 7 – José Manuel Sánchez Nov 29 '13 at 08:37
  • To solve the problems with the indexes, i created a `NSDictionary` containing the titles as keys with `NSNumber` (e.g. `@(0)`) as values. In `actionSheet:clickedButtonAtIndex:` for example i get the title for the specific pressed `buttonIndex` via `buttonTitleAtIndex` on the `actionSheet`. Then i get the value with the title as key from my dictionary and take the `integerValue` of this value to do a `switch-case`. For me this is working great. Don't forget to add the all button titles also cancel etc. to your dictionary – manuelwaldner Jan 21 '16 at 08:25
78

One little note: [actionSheet addButtonWithTitle:] returns the index of that button, so to be safe and "clean" you can do this:

actionSheet.cancelButtonIndex = [actionSheet addButtonWithTitle:@"Cancel"];
Nick
  • 2,498
  • 1
  • 22
  • 28
3

Taking Jaba's and Nick's answers and extending them a little further. To incorporate a destruction button into this solution:

// Create action sheet
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:title
                                                         delegate:self
                                                cancelButtonTitle:nil
                                           destructiveButtonTitle:nil
                                                otherButtonTitles:nil];
// Action Buttons
for (NSString *actionName in actionNames){
    [actionSheet addButtonWithTitle: actionName];
}

// Destruction Button
if (destructiveName.length > 0){
    [actionSheet setDestructiveButtonIndex:[actionSheet addButtonWithTitle: destructiveName]];
}

// Cancel Button
[actionSheet setCancelButtonIndex: [actionSheet addButtonWithTitle:@"Cancel"]];

// Present Action Sheet
[actionSheet showInView: self.view];
Stephen Donnell
  • 800
  • 9
  • 20
2

There is the swift version for the response :

//array with button titles
private var values = ["Value 1", "Value 2", "Value 3"]

//create action sheet
let actionSheet = UIActionSheet(title: nil, delegate: self, cancelButtonTitle: nil, destructiveButtonTitle: nil)
//for each value in array
for value in values{
    //add a button
    actionSheet.addButtonWithTitle(value as String)
}
//display action sheet
actionSheet.showInView(self.view)

To get value selected, add delegate to your ViewController :

class MyViewController: UIViewController, UIActionSheetDelegate

And implement the method "clickedButtonAtIndex"

func actionSheet(actionSheet: UIActionSheet, clickedButtonAtIndex buttonIndex: Int) {
    let selectedValue : String = values[buttonIndex]
}
Kevin ABRIOUX
  • 12,949
  • 7
  • 80
  • 78