46

It could be probably a bug on iOS7. But the last button is not separated from the previous oneUIActionSheet is missing separator on the last button

As you can see from the image. This happens on both Simulator and device using iOS7 GM. Does everyone else has the same problem?

UIActionSheet *actionSheet = [[UIActionSheet alloc]
               initWithTitle:@"Title"
               delegate:self
               cancelButtonTitle:nil
               destructiveButtonTitle:nil
               otherButtonTitles:@"First", @"Second", @"Third", @"Fourth", nil];
[actionSheet showInView:self.view];

As you can see the code is quite simple. Any idea on how to fix the problem? Or some third party library I can use instead of UIActionSheet ?

HpTerm
  • 7,871
  • 12
  • 48
  • 67
Punty
  • 900
  • 2
  • 11
  • 17
  • 2
    Most likely this is an iOS bug. [File a bugreport](https://bugreport.apple.com/). I see something similar in UITableViews. The separators are missing on some rows. I think it's not worth to try to fix this by using a third party library. I'm pretty sure that there will be a GM2 soon. – Matthias Bauch Sep 13 '13 at 16:25
  • 8
    https://devforums.apple.com/message/857939#857939 this suggests a workaround of passing in @"" to the cancelButtonTitle (iPad) – wattson12 Sep 13 '13 at 16:26
  • The workaround worked! – nacho4d Sep 29 '13 at 07:01
  • 1
    @wattson12 this is a good workaround, but if i don't want a cancel button, what can i do? – JJ86 Jan 23 '14 at 15:48

8 Answers8

24

I think ActionSheet requires a cancel button.So you can add the cancel button title.

Another way is: Specify actionSheet's cancelButtonIndex.

For example,in your case, you can add a "Cancel" in otherButtonTitles at index 4 and then specifiy actionSheet.cancelButtonIndex = 4.

Yiding
  • 2,834
  • 3
  • 18
  • 16
  • 4
    At first I didn't think this was ideal, but what I didn't realize is that if you add a cancel button, iPad is smart enough to not display it. (This is true in iOS 6 as well.) Since iPhone should have a cancel button this solution works perfectly. – robotspacer Nov 03 '13 at 02:53
  • 1
    "I think ActionSheet requires a cancel button ..." is not the case. Apple state in the documentation: " ... Specify nil if you do not want a cancel button or are presenting the action sheet on an iPad." However, adding @"" instead of nil works for me as posted below. – Stephen Watson Mar 17 '14 at 13:00
8

I found a way to make it work on iPhone and iPad in the least hacky way:

  1. Only init the UIActionSheet with a title
  2. Add your buttons
  3. Add a "CANCEL" button at last
  4. set the CancelButtonIndex to that last index

I assume that the missing separator is caused by the cancel button not being recognized as a separate case when adding it first or through the init.

teebot
  • 1,049
  • 2
  • 11
  • 24
6

I found that adding a cancel button with an empty string after initialization works. The cancel button won't show up and the separator shows up.

[sheet addButtonWithTitle: @""];
[sheet setCancelButtonIndex: sheet.numberOfButtons - 1];

But this only works for iPad. On iPhone, an empty cancel button shows up, but I found a hacky workaround to make it work. In addition to the above, in willPresentActionSheet add this code in:

NSInteger offset = 55;
CGRect superFrame = actionSheet.superview.frame;
superFrame.origin.y += offset;
[actionSheet.superview setFrame: superFrame];

// hide underlay that gets shifted with the superview
[(UIView*)[[actionSheet.superview subviews] objectAtIndex: 0] removeFromSuperview];

// create new underlay
CGRect underlayFrame = CGRectMake(0, -offset, superFrame.size.width, superFrame.size.height);
UIView* underlay = [[UIView alloc] initWithFrame: underlayFrame];
underlay.alpha = 0.0f;
[underlay setBackgroundColor: [UIColor colorWithWhite: 0.0f alpha: 0.4f]];
[actionSheet.superview insertSubview: underlay atIndex: 0];

// simulate fade in
[UIView animateWithDuration: 0.3f animations:^{
    underlay.alpha = 1.0f;
}];

This shifts down the sheet to hide the cancel button off the screen

HpTerm
  • 7,871
  • 12
  • 48
  • 67
Chris
  • 6,863
  • 17
  • 64
  • 108
5

The simplest fix is to pass @"" to the cancel button title instead of nil during allocation.

UIActionSheet *actionSheet = [[UIActionSheet alloc]
               initWithTitle:@"Title"
               delegate:self
               cancelButtonTitle:@"" // change is here
               destructiveButtonTitle:nil
               otherButtonTitles:@"First", @"Second", @"Third", @"Fourth", nil];
[actionSheet showInView:self.view];
aha
  • 3,474
  • 3
  • 19
  • 27
3
UIActionSheet *asAccounts = [[UIActionSheet alloc]
                            initWithTitle:Localized(@"select_an_account")
                            delegate:self
                            cancelButtonTitle:nil
                            destructiveButtonTitle:nil
                            otherButtonTitles: nil];

for (int i=0; i<[result count]; i++) {
    ACAccount *acct = [result objectAtIndex:i];
    [asAccounts addButtonWithTitle:[acct username]];
    asAccounts.tag = i;
}

[asAccounts addButtonWithTitle:Localized(@"Cancel")];                
asAccounts.cancelButtonIndex = result.count;
[asAccounts showInView:self.view];
HpTerm
  • 7,871
  • 12
  • 48
  • 67
nesimtunc
  • 621
  • 4
  • 23
1

If you have a cancel button, the last row will be shown. That is the temp fix I am using now. Do not know any solution if you do not want a cancel button to show

0

It seems that the initWithTitle:delegate:cancelButtonTitle:destructiveButtonTitle:otherButtonTitles: method is buggy and you shouldn't specify any cancel button here at all. Btw, it seems that a destructive button set in that method also won't work very well.

Instead of it you should:

  • provide a custom cancel button as the last button in the buttons array, eg: ["Action 1", "Action 2", "Close"] or sheet.addButtonWithTitle("Close")
  • manually set the cancel button index, e.g. sheet.cancelButtonIndex = 2

Then everything will work as expected. On the iPad the button will be automatically hidden and on the iPhone it will be styled and placed in the proper way.

Dmitry Sokurenko
  • 5,449
  • 3
  • 27
  • 46
0
    - (void)willPresentActionSheet:(UIActionSheet *)actionSheet {
    if ([UIDevice currentDevice].systemVersion.floatValue < 8.0f) {
        UIView *separator = [[UIView alloc] initWithFrame:CGRectMake(8, 88, actionSheet.frame.size.width - 16, 0.5)];
        separator.backgroundColor = [UIColor colorWithRed:219.0f/255 green:219.0f/255 blue:223.0f/255 alpha:1];
        [actionSheet addSubview:separator];
    }
}

Every button has height 44. My actionSheet doesn't have title. And I wanted to add separator between second and third buttons. That's why I use number 88.