10

I need to disable the buttons in UIActionSheet. after some operations i need to enable them again. So is there a way to do this.

Thanks

satish
  • 1,245
  • 3
  • 14
  • 15

6 Answers6

17

Based on a number of thread, i've aggregated an answer into a category on UIActionSheet, adding a setButton:toState method as follows. Hope it helps:

@interface UIActionSheet(ButtonState)
- (void)setButton:(NSInteger)buttonIndex toState:(BOOL)enbaled;
@end

@implementation UIActionSheet(ButtonState)
- (void)setButton:(NSInteger)buttonIndex toState:(BOOL)enabled {
    for (UIView* view in self.subviews)
    {
        if ([view isKindOfClass:[UIButton class]])
        {
            if (buttonIndex == 0) {
                if ([view respondsToSelector:@selector(setEnabled:)])
                {
                    UIButton* button = (UIButton*)view;
                    button.enabled = enabled;
                }
            }
            buttonIndex--;
        }
    }
}
@end
Reuven
  • 2,142
  • 3
  • 18
  • 30
3

Swift 3.0 version:

let actionSheet = UIAlertController(title:nil, message:nil, preferredStyle:UIAlertControllerStyle.actionSheet)


actionSheet.addAction(UIAlertAction(title:"Modify", style:UIAlertActionStyle.default, handler:{ action in
    // Do your thing here
}))

let disabledDelete = UIAlertAction(title:"Cannot delete this item", style:UIAlertActionStyle.destructive, handler:nil)
disabledDelete.isEnabled = false
actionSheet.addAction(disabledDelete)

actionSheet.addAction(UIAlertAction(title:"Cancel", style:UIAlertActionStyle.cancel, handler:nil))

self.present(actionSheet, animated:true, completion:nil)
Hakim
  • 1,242
  • 1
  • 10
  • 22
2

Slightly improved version of Reuven's [alas I cant add a comment to his 'cause I dont have the 'reputation' yet...].

@interface UIActionSheet (ButtonEnabled)
- (void)setButtonAtIndex:(NSUInteger)index Enabled:(BOOL)enabled;
@end

@implementation UIActionSheet (ButtonEnabled)
- (void)setButtonAtIndex:(NSUInteger)index Enabled:(BOOL)enabled
{
    for (UIView* view in self.subviews) {
        if ([view isKindOfClass:[UIButton class]]) {
            if (index-- == 0) {
                [(UIButton*)view setEnabled:enabled];
                break;
            }
        }
    }
}
@end

The previous respondsToSelector: check was extraneous, because we are already checking for UIButton (which is a UIControl subclass, which all support setEnabled]. In keeping with Apple's NSArrays, I also changed to "AtIndex" and NSUInteger, but that's mostly cosmetic.

The overall approach seems to work fine, but please note it does assume the order of the button subviews precisely matches the order of the button indexes when the action sheet was constructed, which isn't strictly documented anywhere AFAIK.

tiritea
  • 1,229
  • 13
  • 18
  • BTW, according to [this](http://stackoverflow.com/questions/5262428/uiactionsheet-buttonindex-values-faulty-when-using-more-than-6-custom-buttons), the button indexes *do* go haywire when you have too many items in your action sheet. So that will screw up this approach (for disabling) if you have to many. – tiritea Aug 22 '14 at 02:36
1

The provided solutions do not work on iOS 8. In case anyone is not using the UIAlertController for this (which is Apple's recommended way of doing it) this is how I modified @Reuven's answer to work for iOS 8 too:

(the second phase is based on this so answer)

- (void)setButton:(NSInteger)buttonIndex toState:(BOOL)enabled {

    SEL selector = NSSelectorFromString(@"_alertController");

    //iOS 8
    if ([self respondsToSelector:selector]) {

        UIAlertController *alertController = [self valueForKey:@"_alertController"];

        if ([alertController isKindOfClass:[UIAlertController class]]){

            UIAlertAction *action = alertController.actions[buttonIndex];

            [action setEnabled:enabled];

        }

    //iOS 7
    }else{

        for (UIView* view in self.subviews){

            if ([view isMemberOfClass:NSClassFromString(@"UIAlertButton")]) {

                if (buttonIndex == 0) {

                    if ([view respondsToSelector:@selector(setEnabled:)]){

                        UIButton* button = (UIButton*)view;

                        button.enabled = enabled;

                    }

                }

                buttonIndex--;

            }

        }

    }

}
Community
  • 1
  • 1
Petar
  • 2,241
  • 1
  • 24
  • 38
0

This is probably a bit late. But, the way I figured out is create UIButton(s) and add them to UIActionSheet subview. Make certain these buttons are placed on top and completely cover the default UIActionSheet button(s) to replace. When the UIButton is placed over the default UIActionSheet button, its UIResponder takes precedence over UIActionSheet button UIResponder. So, doing so you can disable and enable those buttons however you'd like anywhere in you UIViewController logic. This may be an alternative to accessing private methods to the SDK (like above - UIThreePartButton) and apple might reject your app. I believe this follows the Apple guidelines.

i.e.

// Instantiate once
if (self.actionSheet==nil)  {
    UIActionSheet *as = [[UIActionSheet alloc] 
                         initWithTitle:@""
                         delegate:self 
                         cancelButtonTitle:@"Cancel"
                         destructiveButtonTitle:@"Load Data"
                         otherButtonTitles:@"Update Data",nil];

    //[actionSheet showInView:self.view];
    self.loadUIButton.frame = CGRectMake(24.0f,25.0f,275.f,46.0f);
    [as addSubview: self.loadUIButton];
    self.updateUIButton.frame = CGRectMake(24.0f,78.0f,275.f,46.0f);
    [as addSubview: self.updateUIButton];
    //[actionSheet addSubview: self.cancelUIButton];
    //[as showFromToolbar: self.navigationController.toolbar];
    self.actionSheet = as;
    [as release];
}
[self.actionSheet showFromToolbar: self.navigationController.toolbar];
-2

Thees buttons are subviews of UIActionSheet and their class is UIThreePartButton

You can get them and do all that you want:

UIActionSheet *a = [[UIActionSheet alloc]initWithTitle:@"" delegate: nil cancelButtonTitle: @"c" destructiveButtonTitle: @"d" otherButtonTitles: @"ot", nil];
    [a showInView: window];

    for(UIView *v in [a subviews])
    {
        if([[v description] hasPrefix: @"<UIThreePartButton"] )
        {
            v.hidden = YES;  //hide
           //((UIButton*)v).enabled = NO;   // disable

        }
    }
oxigen
  • 6,263
  • 3
  • 28
  • 37
  • 3
    I would suggest you do not use this method as these are private to the SDK. Apple might reject your app. The best alternative would be to not show these buttons at all instead of disabling them – lostInTransit Jul 22 '09 at 09:51
  • There is no private methods in this code )) Only public :) Sometimes I use private methods in my apps. I use them once-twice in application and apple didn't reject these apps – oxigen Jul 22 '09 at 11:45
  • 6
    It's not just getting rejected by Apple, use of private API shows a lack of respect for your customers. Private API are private because Apple is still locking them down, so if and when they change, your application will break. View traversal like you described above caused a number of applications to break under 3.0, so much so that Apple called this out in the release notes and said not to do this. – Brad Larson Jul 22 '09 at 12:22