Accessing UIPopoverController for UIActionSheet on iPad

21,592

Solution 1

You would need to adjust on orientation change.

I have found an alternative solution, that works perfectly for me.

Stick to

- (void)showFromBarButtonItem:(UIBarButtonItem *)item animated:(BOOL)animated

In your @interface add

UIActionSheet *popoverActionsheet;

also add

@property (nonatomic, retain) UIActionSheet *popoverActionsheet;

also add

- (IBAction)barButtonItemAction:(id)sender;

So you have reference to your actionsheet from anywhere in your implementation.

in your implementation

- (IBAction) barButtonItemAction:(id)sender
{
    //If the actionsheet is visible it is dismissed, if it not visible a new one is created.
    if ([popoverActionsheet isVisible]) {
        [popoverActionsheet dismissWithClickedButtonIndex:[popoverActionsheet cancelButtonIndex] 
                                                     animated:YES];
        return;
    }

    popoverActionsheet = [[UIActionSheet alloc] initWithTitle:nil
                                                     delegate:self
                                            cancelButtonTitle:nil 
                                       destructiveButtonTitle:nil
                         otherButtonTitles:@"Save Page", @"View in Safari", nil];

    [popoverActionsheet showFromBarButtonItem:sender animated:YES];
}

in your actionsheet delegate implement

- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex
{

    if (buttonIndex == [actionSheet cancelButtonIndex]) return;

    //add rest of the code for other button indeces
}

and don't forget to release popoverActionsheet in

- (void)dealloc

I trust that this will do.

Solution 2

    if ([[[[actionSheet superview] superview] nextResponder] respondsToSelector:@selector(setPassthroughViews:)]) {
        [[[[actionSheet superview] superview] nextResponder] performSelector:@selector(setPassthroughViews:) withObject:nil];
    }

Will do the trick, this shouldn't cause any problems with the App Reviewers either as its not calling any private APIs.

It is fragile - the if statements ensures your code won't crash (just not work) in the unlikely event Apple change the underlying implementation.

Solution 3

I doubt there's a sanctioned approach to this since actionsheets are presented in UIPopoverViews which is linked to a UIViewController not a UIPopoverController

NSLog(@"%@",[[[popoverActionsheet superview] superview] passthroughViews]);

Looking through the UIPopoverView header file (UNDOCUMENTED) yields the following solution albeit undocumented. Doubt you can snick that past the App Reviewers but give it a go if you think it's worth a shot.

http://github.com/kennytm/iphone-private-frameworks/blob/master/UIKit/UIPopoverView.h

NSArray *passthroughViews = [[[popoverActionsheet superview] superview] passthroughViews];

        NSMutableArray *views = [passthroughViews mutableCopy];
        [views addObject:[self view]];
        [[[popoverActionsheet superview] superview] setPassthroughViews:views];
        [views release];

Solution 4

I've been using nbransby's answer for a couple years, but that no longer works in iOS 8. However, the problem still exists with the new UIAlertController in iOS 8. Here's an update that works for me:

UIAlertController *actionSheet = [UIAlertController
    alertControllerWithTitle:@"Test"
    message:@"Hello, world!"
    preferredStyle:UIAlertControllerStyleActionSheet];
[actionSheet addAction:[UIAlertAction
    actionWithTitle:@"OK"
    style:UIAlertActionStyleDefault
    handler:^(UIAlertAction *action) {}]];
actionSheet.modalPresentationStyle = UIModalPresentationPopover;
actionSheet.popoverPresentationController.barButtonItem = testButton;
[self presentViewController:actionSheet animated:TRUE completion:^(void) {
    actionSheet.popoverPresentationController.passthroughViews = [NSArray array];
}];

Note that passthroughViews has to be set after the popover appears, but you can conveniently use the completion block to do that.

Solution 5

I don't think that's feasible. I was sitting with the same problem.

Use

- (void)showFromRect:(CGRect)rect inView:(UIView *)view animated:(BOOL)animated

Example:

[actionSheet showFromRect:[[[myToolBar subviews] objectAtIndex:0] frame] inView:myToolBar animated:YES];

Note: You must change the index for objectAtIndex: to fit your situation and have reference to your ToolBar

Share:
21,592
westsider
Author by

westsider

I have a passion for developing technology that empowers people with its simplicity and elegance. Across programming languages, operating systems and hardware I have been doing this for more than 30 years. I started in BASIC-Plus on PDP-11/34 running RSTS/E - continued through FORTRAN, Pascal, several dialects of Lisp and from Xerox Lisp Machines to Mac, SPARC, Newton, Linux and on to iOS and Android.

Updated on December 24, 2020

Comments

  • westsider
    westsider over 3 years

    On the iPad, one can show a UIActionSheet using -showFromBarButtonItem:animated:. This is convenient because it wraps a UIPopoverController around the action sheet and it points the popover's arrow to the UIBarButtonItem that is passed in.

    However, this call adds the UIBarButtomItem's toolbar to the list of passthrough views - which isn't always desirable. And, without a pointer to the UIPopoverController, one can't add other views to the passthrough list.

    Does anyone know of a sanctioned approach to getting a pointer to the popover controller?

    Thanks in advance.

  • westsider
    westsider about 14 years
    Does that work through changes of orientation? Or do you need to adjust on rotation events? Thanks.
  • westsider
    westsider about 14 years
    Stalinkay, thanks. What you describe is close to what I am doing now. I should have been more specific. I have my action sheet shown from a button in a toolbar at the bottom of screen. I also have a navigation bar across the top of the screen. I would like buttons in the nav bar to behave the same (with respect to action sheet) as buttons in toolbar. In other words, I would like nav bar buttons to be on action sheet's popover's passthrough list - and to have taps in nav bar buttons both dismiss action sheet and handle button event. This is why getting pointer to popover is important.
  • westsider
    westsider about 14 years
    I think that this is what I was looking for - at some level. It is, obviously, fragile to the extent that Apple could change the underlying implementation by, say, adding another layer of views, etc. I am tempted to write my own version with popover. When I get around to that, I will post code here. Thanks, again!
  • stalinkay
    stalinkay about 14 years
    Great. Would like to see what you come up with.
  • DrMickeyLauer
    DrMickeyLauer over 11 years
    This is a good solution. I wonder though why Apple adds the bar to the passthroughviews in the first place.
  • Greg Maletic
    Greg Maletic over 11 years
    This doesn't work for me on iOS 6. The popover controller is not in the responder chain.
  • ToddH
    ToddH about 11 years
    Work great for me on iOS 6! It has to be called after the action sheet is presented.
  • Byte
    Byte over 10 years
    Very well workaround (might even be the best one here). I don't know why people don't upvote this.