Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dismissing UIActionSheet from UIBarButtonItem on an iPad

I have a UIToolbar with several UIBarButtonItems that show various UIActionSheets using showFromBarButtonItem:.

On the iPad, when one of those Action Sheets is on the screen, touching anywhere outside the Action Sheet removes it and does nothing else (e.g. touching a button does not trigger the button). This is by design - something that I'm not happy about but I accept it as long as it's the usual behavior.

There's one exception though. If I touch another UIBarButtonItem, this button IS triggered and the current action sheet is NOT removed from the screen. If the new button happens to launch another UIActionSheet, I end up having two (or more) action sheets on the screen.

Of course I can go go through a tedious process of remembering what's on the screen and dismissing it manually, but I'm also concerned about the user since some touches (those that target the toolbar buttons) are honored while others are ignored.

Is there anything that I can do or do I have to live with this situation?

like image 789
Amiram Stark Avatar asked Dec 03 '11 21:12

Amiram Stark


1 Answers

This does seem to be an annoying inconsistency, but not a hard one to rectify. This example assumes you only need to show UIActionSheets which seems like it's the case with you.

Here is a functioning example of how to fix this, starting with the .h:

@interface TestToolBarExclusiveActionSheet : UIViewController <UIActionSheetDelegate>{
    UIActionSheet *sheetShowing;
}
@property (weak, nonatomic) IBOutlet UIBarButtonItem *oneButton;
@property (weak, nonatomic) IBOutlet UIBarButtonItem *twoButton;
@end

and the .m:

#import "TestToolBarExclusiveActionSheet.h"
@implementation TestToolBarExclusiveActionSheet
@synthesize oneButton;
@synthesize twoButton;
-(IBAction)targetForBothButtons:(UIBarButtonItem *)button{
    if (sheetShowing != nil){
        [sheetShowing dismissWithClickedButtonIndex:[sheetShowing cancelButtonIndex] animated:YES];
        sheetShowing = nil;
    }
    else{ // I am free to act on the button push.
        // Just for demo.. So:
        sheetShowing = [[UIActionSheet alloc] initWithTitle:button.title delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Destroy" otherButtonTitles:nil, nil];
        [sheetShowing showFromBarButtonItem:button animated:YES];
    }
}
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
    sheetShowing = nil;
    // Respond to action sheet like normal
}
-(void)viewDidUnload{
    [self setOneButton:nil];
    [self setTwoButton:nil];
    [super viewDidUnload];
}
@end

and finally a screenshot of the .xib (shown in iPhone mode for image size):

enter image description here

Simply connect the button outlets and connect both button actions to the targetForBothButtons: method.

You'll see that if one of the action sheets is showing then pushing any bar button will result in the dismissal of the action sheet.

like image 100
NJones Avatar answered Nov 16 '22 02:11

NJones