UIActionSheet buttonIndex values faulty when using more than 6 custom buttons?

12,342

Solution 1

I ran into the same issue even though I already was including the Cancel Button as the last one in the action sheet and setting its index accordingly. My problems had to do with the 'Destructive' button. After some investigation, here is my take on the problem:

  • After N buttons have been added to the actionsheet, it switches its layout to put the Destructive button at the top and the Cancel button at the bottom. In between is a scrollable view that includes all of the other buttons. Other sources indicate that this is a a table view.

  • N is 7 for Portrait orientation and 5 for Landscape orientation. N is 9 for Portrait orientation on larger, 4" screen. These numbers are for all buttons including Cancel and Destructive. To be clear, N is the largest number of buttons before the switch. N+1 buttons causes the UIActionSheet to switch to the scrollable view.

  • It does not matter where in the action sheet you had originally put the Cancel and Destructive buttons within the action sheet. Once the limit has been reached, the Destructive button is moved to the top and the Cancel is moved to the bottom.

  • The problem is that the indices are not adjusted accordingly. So, if you did not initially add the Cancel as the last button and the Destructive as the first, the wrong index will be reported in actionSheet:clickedButtonAtIndex: as the initial report stated.

  • So, if you are going to have more than N buttons in your action sheet you MUST add the Destructive button to the actionSheet as the first button to the action sheet. You MUST add the Cancel button as the last button added to the action sheet. When initially constructing the sheet just leave both as nil, as described in another answer.

Solution 2

I've just had this problem. Solve it by not setting the cancel button initially. I set the buttons individually something like this:

   for(int index = 0; index < buttonTotal; index++)
   {
    [actionSheet addButtonWithTitle:[NSString stringWithFormat:buttonText, [buttonItems objectAtIndex: index]]];
   }

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

I believe the zero index is used by the destructiveButton if you use it so the other buttons will increment from there, otherwise they will start from 0.

Not sure I agree with the table option since above a certain amount, the buttons default to a scrollable list.

Solution 3

1) Instantiate the actionview using

[[UIActionSheet alloc] InitWithTitle:delegate:cancelButtonTitle:destructiveButtonTitle:OtherButtonTitles:]

without either the cancel button or destructive button (set them to nil)

2) Add all of the buttons as normal, using [myActionSheet addButtonWithTitle:(NSString *)].

3) If you want a special button, add it using the same method as step 2, and set the title to whatever (@"Cancel", for instance);

4) Now set the property [myActionSheet setCancelButtonIndex:] to the index of the last button on the actionsheet, which was the cancel button made. Do the same for a destructive button. (These are -1 by default, which causes them not to be shown)

  • Note that a destructive button will always appear on top, and a cancel button will always appear on bottom, that cannot be changed.

  • Also, you can certainly add the cancel/destructive button at index 0, and add all of the other buttons after that. However now the first index of your other buttons is 1, instead of zero. This can be confusing if you have an array that corresponds with the alertview buttons.

Solution 4

file a bug about the problem. Include a little sample project and wait for some months to hear back from them.

For now you can set up your buttons statically in the init

UIActionSheet *actionSheet = [[UIActionSheet alloc] 
                              initWithTitle:@"TestSheet" 
                              delegate:self 
                              cancelButtonTitle:@"Cancel" 
                              destructiveButtonTitle:nil 
                              otherButtonTitles: @"one", @"two", @"three", @"four", @"five", @"six", @"seven", nil];

works without problems.

Share:
12,342

Related videos on Youtube

huesforalice
Author by

huesforalice

Updated on May 24, 2022

Comments

  • huesforalice
    huesforalice about 2 years

    I have discovered a strange problem when using UIActionSheet on the iPhone (iOS 4.2). Consider this code:

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    
    
        [self.window addSubview:viewController.view];
        [self.window makeKeyAndVisible];
    
        UIActionSheet *actionSheet = [[UIActionSheet alloc] 
                                      initWithTitle:@"TestSheet" 
                                      delegate:self 
                                      cancelButtonTitle:@"Cancel" 
                                      destructiveButtonTitle:nil 
                                      otherButtonTitles: nil];
    
        [actionSheet addButtonWithTitle:@"one"];
        [actionSheet addButtonWithTitle:@"two"];
        [actionSheet addButtonWithTitle:@"three"];
        [actionSheet addButtonWithTitle:@"four"];
        [actionSheet addButtonWithTitle:@"five"];
        [actionSheet addButtonWithTitle:@"six"];
        //uncomment next line to see the problem in action
        //[actionSheet addButtonWithTitle:@"seven"];
    
        [actionSheet showInView:window];
        [actionSheet release];
    
        return YES;
    }
    - (void) actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
        NSLog(@"buttonIndex: %d, cancelButtonIndex: %d, firstOtherButtonIndex: %d",
              buttonIndex, 
              actionSheet.cancelButtonIndex, 
              actionSheet.firstOtherButtonIndex);
    }
    

    If you start this application, the actionsheet behaves as expected. That means the cancelButtonIndex is always 0, and the button indexes are reported correctly. 1 for button "one" and so on. If you comment in the line for adding the seventh button, the actionsheet produces a sort of tableview, with the cancel button on an extra line. If I press the "one" button in this case, the buttonindex variable is 0, but so is the cancelButtonIndex. It is impossible to tell if the user has tapped the "cancel" or the "one" button. That doesn't seem like it should be this way. Does anyone disagree? Thanks for your help.

    • huesforalice
      huesforalice over 13 years
      Well what's the point of having an actionsheet which can handle more than 6 buttons in a scrollview if you're not supposed to use it?
  • huesforalice
    huesforalice over 13 years
    Thanks for your tip, I need to set the buttons from an array though, the above was just an example to point out that the addButtonWithTitle method doesn't seem to work.
  • user102008
    user102008 almost 13 years
    you should just do actionSheet.cancelButtonIndex = [actionSheet addButtonWithTitle:@"Cancel"];
  • Christopher
    Christopher about 12 years
    This is the actually correct answer - not the one marked above. Thanks to Rich for posting. For readers, take note of the fourth bullet with respect to ordering of buttons.
  • stephenmuss
    stephenmuss over 11 years
    This is such ridiculous behaviour. I often wonder why Apple makes certain decisions. This is one of them. Thanks for the tip.
  • Ege Akpinar
    Ege Akpinar about 11 years
    Wouldn't localisation break this solution?
  • Ege Akpinar
    Ege Akpinar about 11 years
    I was thinking localisation would break this solution (due to different 'Cancel' strings in different locales). Just implemented @user102008 's solution and it works without problems (it must be determining the cancel button based on the index, not the string)