views:

3107

answers:

7

I want to disable buttons in the UIAction sheet and enable them after a certain condition is true. How do I achieve this? Any ideas?

A: 

Unfortunately, there is no way to access the buttons through any "official" means, though a workaround is available.

Since the UIActionSheet is a subclass of UIView, you can obtain a list of its subviews. Each one of the subviews is one of the UIButton objects in the sheet. (You can do a class check just to make sure.) At that point you will have references to the buttons, and can perform whatever operations you wish:

NSArray *buttons = [actionSheet subviews];

for (NSObject *object in buttons) {
    if ([object isKindOfClass:[UIButton class]]) {
        UIButton *button = (UIButton *)object;
        if ([[button currentTitle] isEqualToString:@"Button 1"]) {
            // Do things with button1.
        }
    }
}
craig
This didn't work for me on OS3.1. I discovered that the subviews of UIActionSheet are now instances of UIThreePartButton which is not derived from UIButton. I guess Apple must have chnaged the internals as part of the OS update. See my answer for an alternative on OS3.1
cidered
You should NEVER make assumptions on the internals of any class unless it is officially documented. Apple will (and historically have) change the implementation whenever they see fit. If Apple can rewrite their code with better performance or memory footprint withour breaking public API:s; then they will, and they will NOT test if YOUR app works first.
PeyloW
+2  A: 

Is there a circumstance that can change, while the action sheet is open, that could cause the button to become enabled? If not, I think the better approach is to alter the buttons that the sheet displays based on your condition.

Otherwise, the only way of handling this is to iterate through the sheet's subviews, like Craig said, and look for the UIButton objects. I'd be careful about using the button's title, though, because the title could (and should!) be localized for different languages. So comparisons against the title aren't all that reliable. Since you didn't create the button, you don't really know what the tag or action of each button would be, either, so that's a bit difficult, too.

Presumably, the buttons will appear in the subviews array in the order you specified them to the UIActionSheet, but since this isn't documented, there's no guarantee that they will appear in that order, or that they will continue to appear in that order in future releases of the Cocoa Touch SDK. Because of that, I'd worry mainly about being rejected from the App Store for using undocumented functionality.

Alex
You wouldn't be rejected from the App Store for this procedure. There's always a chance that Apple will change the subview order, and your application might start acting strange, but it is not the type of 'undocumented funcionality' that they would prohibit from the store.
craig
True, it's not the same thing as private API, but it is private in the sense that it's based on experiment, not documentation. I would very strongly recommend against it. I'm not confident that Apple wouldn't reject it -- the agreement gives them a free hand in rejecting apps for any reason.
Alex
A: 

Hi there,

Is there a way to add our own view to an UIActionSheet? That is, I want to provide list of links to other views from this action sheet without buttons. I want to remove buttons in that action sheet and instead I should add list of items.

Please provide me a quicker solution, as I am in desperate need of this.

Thanks

You should ask a new question, rather than posting this as an answer to another question.
Daniel Rinser
A: 

If you add the view to the action sheet, the view wont receive any event. You need to the view to the superview of the action sheet.

See below how i've added an button with touch up event:

- (void)didPresentActionSheet:(UIActionSheet *)actionSheet{
CGRect rect = CGRectMake(0,0, 320, 480);
UIButton* anImage = [[UIButton alloc] init];
[anImage setTitle:@"GHello worl" forState:UIControlStateNormal];
[anImage setTitle:@"GHello worl dfasd" forState:UIControlStateHighlighted];
[anImage setTitle:@"GHello worl selected" forState:UIControlStateSelected];
//[anImage setBackgroundImage:[UIImage imageNamed:@"photo.png"] forState:UIControlStateNormal];
[anImage addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
rect = CGRectMake(0,0, 320, 220);
anImage.frame =rect;


[actionSheet.superview addSubview:anImage];



[anImage release];

}

Shaikh Sonny Aman
+1  A: 

I found that craig's answer didn't work for me (on OS 3.1). After a little digging around I discovered that the subviews of UIActionSheet are actually of an undocumented class UIThreePartButton

Anyway, this works for me (implemented as part of the UIActionSheetDelegete method)

- (void)willPresentActionSheet:(UIActionSheet *)actionSheet  // before animation and showing view
{
    for (UIView* view in [actionSheet subviews])
    {
        if ([[[view class] description] isEqualToString:@"UIThreePartButton"])
        {
            if ([view respondsToSelector:@selector(title)])
            {
                NSString* title = [view performSelector:@selector(title)];
                if ([title isEqualToString:@"Button 1"] && [view respondsToSelector:@selector(setEnabled:)])
                {
                    [view performSelector:@selector(setEnabled:) withObject:NO];
                }
            }
        }
    }
}

Hope that helps someone else, although I'd echo Ed Marty's question of whether you'd be better off just omitting these buttons from the action sheet altogether instead of doing this. As always when using undocumented features, there is a risk of app store rejection, although this code is written to fail gracefully if Apple do chnage the APIs again in a future OS release.

cidered
Never use `description` for comparing classes. Correct way is to use use `[view isKindOfClass:NSClassFromString(@"UIThreePartButton")];`
porneL
Using undocumented classes like this is a sure way to get rejected when submitting to App Store.
PeyloW
@PeyloW - which is exactly what was written in the post. Your comment does not add any value here.
cidered
A: 

UIActionSheet is not intended for customizing. It should display actual set of available options. It should not change button's availability while on top. Just remove unused buttons, or use custom view instead

vaddieg
A: 

I faced a similar problem when I had an action sheet that changes based on some conditions. I omitted the choices that are not applicable from the action sheet altogether but in some cases I end up with an action sheet with just one choice. This seems a bit silly, since I could activate that choice immediate without displaying the sheet at all.

However, I also want users to learn that clicking a certain button on screen gives them a list of choices they can choose from. That's why I want to display the action sheet also in cases when it has just one choice. I thought about disabling the non-applicable choices instead of omitting them from the sheet but that didn't feel right, either.

My case is related to having a user-icon in a custom bottom bar and pressing it presents the following choices:

  • if logged in
    • My Profile
    • Log out
  • if not logged in
    • Log in
Mayoneez