Question

I am trying to create a UIAlertView with three buttons (which will be stacked). I would like the Cancel button to be in the middle, between the two other buttons. I have tried setting the cancelButtonIndex to 1, but if there are two other buttons, it simply places them at indexes 0 and 1. I know I could just change the names of the buttons, but I want the darker blue formatting of the cancel button.

EDIT: ** Please note - I know how to get the three buttons with the titles in the correct order, but only if all three buttons essentially look like 'other' buttons; I want the cancel button to have the cancel button dark blue background so that it will look like a regular cancel button. **

I've tried

UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:title message:msg delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:button1Title,button2Title,nil] autorelease];
alert.cancelButtonIndex = 1;
[alert show];

and

UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:title message:msg delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:nil] autorelease];
alert.cancelButtonIndex = 1;
[alert addButtonWithTitle:button1Title];
[alert addButtonWithTitle:button2Title];
[alert show];

and

UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:title message:msg delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:addButtonWithTitle:button1Title,nil] autorelease];
alert.cancelButtonIndex = 1;
[alert addButtonWithTitle:button2Title];
[alert show];

to no avail. Is it even possible to accomplish what I am trying to do?

Was it helpful?

Solution

I have two ancillary points to this answer.

1) While, to the best of my knowledge, Apple has not rejected an app for reasonable modification of a UIAlertView; They have said that the view hierarchy of classes like UIAlertView should be considered private.

2) This question is a good example of why you should ask a question more about your end goal rather than the steps to get there. The only reason I know what this question is about is as a result of a comment left at my answer here.

Answer:

Because of your comment I know that you are looking to create a UIAlertView that has stacked buttons even when there are only 2 buttons.

I find the most logical place for code like this is in a category. Since generally the code needed to manipulate the alert-view needs to be around the show call, I created a category method I call instead of show and the method in turn calls show itself.

-(void)showWithButtonsStacked{
    static NSString *tempButtonTitle = @"SomeUnlikelyToBeUsedTitle";
    BOOL willAddFakeButton = (self.numberOfButtons == 2); // Button are only side by side when there's 2
    if (willAddFakeButton){
        self.clipsToBounds = YES;
        [self addButtonWithTitle:tempButtonTitle]; // add temp button so the alertview will stack
    }
    BOOL hasCancelButton = (self.cancelButtonIndex != -1); // If there is a cancel button we don't want to cut it off
    [self show];
    if (willAddFakeButton){
        UIButton *cancelButton = nil;
        UIButton *tempButton = nil;
        for (UIButton *button in self.subviews) {
            if ([button isKindOfClass:[UIButton class]]){
                if (hasCancelButton && [button.titleLabel.text isEqualToString:[self buttonTitleAtIndex:self.cancelButtonIndex]]){
                    cancelButton = button;
                } else if ([button.titleLabel.text isEqualToString:tempButtonTitle]) {
                    tempButton = button;
                }
            }
        }
        if (hasCancelButton){ // move in cancel button
            cancelButton.frame = tempButton.frame;
        }
        [tempButton removeFromSuperview];

        // Find lowest button still visable.
        CGRect lowestButtonFrame = CGRectZero;
        for (UIButton *button in self.subviews) {
            if ([button isKindOfClass:[UIButton class]]){
                if (button.frame.origin.y > lowestButtonFrame.origin.y){
                    lowestButtonFrame = button.frame;
                }
            }
        }

        // determine new height of the alert view based on the lowest button frame
        CGFloat newHeight = CGRectGetMaxY(lowestButtonFrame) + (lowestButtonFrame.origin.x * 1.5);
        self.bounds = CGRectMake(0, 0, self.bounds.size.width, newHeight);        
    }
}

The way this method accomplishes it's goal is to add a temporary button to the alert-view to force the alert-view to stack the buttons, then it removes the temporary button and adjusts the height. Since it's a category method you use it simply by calling:

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Test title" message:@"message" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"OK", nil];
[alert showWithButtonsStacked];

This code results in an alert like this:

enter image description here

OTHER TIPS

UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:title message:msg delegate:self        cancelButtonTitle:nil otherButtonTitles:nil] autorelease];
[alert addButtonWithTitle:button1Title];
[alert addButtonWithTitle:@"Cancel"];
[alert addButtonWithTitle:button2Title];
[alert show];

Might Help,

Cheers.

UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:title message:msg delegate:self cancelButtonTitle:nil otherButtonTitles:nil] autorelease];
[alert addButtonWithTitle:button1Title];
[alert addButtonWithTitle:@"Cancel"];
[alert addButtonWithTitle:button2Title];
[alert setCancelButtonIndex:1]; // to make it look like cancel button
[alert show];

Set the cancel button to nil and just add it in the other buttons instead

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top