Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIStoryboardPopoverSegue opening multiple windows on button touch

Tags:

iphone

ios5

I'm using a UIStoryboardPopoverSegue to present a popover for an iOS 5 iPad app. The Segue works great, but it seems like the toolbar that contains the button is a passthrough view for the popover controller so if you keep pressing the button, more popovers appear. As I'm not creating and keeping track of the UIPopoverController myself (as the Storyboard is doing it) I can't dismiss it when the button is touched again. Has anyone else run into this? I have a bug open with Apple but they haven't responded.

EDIT: I've solved this using the answer below. Here is the code I ended up using. currentPopover is a __weak ivar in my view controller class, so when the controller is done it will drop to nil automatically.

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
    if([segue isKindOfClass:[UIStoryboardPopoverSegue class]]){
        // Dismiss current popover, set new popover
        [currentPopover dismissPopoverAnimated:YES];
        currentPopover = [(UIStoryboardPopoverSegue *)segue popoverController];
    }
}
like image 228
Cory Imdieke Avatar asked Oct 13 '11 18:10

Cory Imdieke


3 Answers

There are some visual issues with the your solution Cory.

Two options that can be considered - simply remove or change the action of the button that presents the popover.

Option 1, hold a pointer to the button's action, and after the popover is presented, set the action to nil. Upon dismissal of the popover reset to the original action.

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{

    action = [sender action];
    [sender setAction:nil];

    self.currentPopover = [(UIStoryboardPopoverSegue *)segue popoverController];
    self.currentPopover.delegate = self;
}

-(BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController
{
    [self.navigationItem.rightBarButtonItem setAction:action];

    return YES;
}

This way the popover can only appear once, and will be dismissed as expected.

A second option would be to change the function of the button so that when the popover is visible, tapping the button will cause the popover to be dismissed.

    -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
    {

        action = [sender action];
        target = [sender target];

        [sender setTarget:self];
        [sender setAction:@selector(dismiss:)];

        self.currentPopover = [(UIStoryboardPopoverSegue *)segue popoverController];
        self.currentPopover.delegate = self;
    }

-(void)dismiss:(id)sender
{
    [self.navigationItem.rightBarButtonItem setAction:action];
    [self.navigationItem.rightBarButtonItem setTarget:target];
    ////or
//  [sender setAction:action];
//  [sender setTarget:target];
    [self.currentPopover dismissPopoverAnimated:YES];
}


    -(BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController
    {
        [self.navigationItem.rightBarButtonItem setAction:action];
        [self.navigationItem.rightBarButtonItem setTarget:target];

        return YES;
    }
like image 59
Robert Sammond Avatar answered Oct 18 '22 01:10

Robert Sammond


Simply connect a UIBarButtonItem via IBAction. Use the itendifier set in interface builder:

-(IBAction)barButtonItemPressed:(id)sender {
    if (currentPopoverController && currentPopoverController.popoverVisible) {
        [currentPopoverController dismissPopoverAnimated:YES];
        currentPopoverController = nil;
    } else {
        [self performSegueWithIdentifier:@"aSegueIdentifier" sender:sender];
    }
}

Get a reference of the new UIPopoverCOntroller from the seque:

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if ([[segue identifier] isEqualToString:@"aSegueIdentifier"])
        currentPopoverController = [(UIStoryboardPopoverSegue *)segue popoverController];
}

currentPopoverController is an instance variable, defined in header file:

UIPopoverController *currentPopoverController;

Important: The anchor property of the seque must be set to the corresponding UIBarButtonItem!

like image 45
Der Ditsch Avatar answered Oct 18 '22 01:10

Der Ditsch


You have to store a reference to the popoverController property passed as part of the UIStoryboardPopoverSegue class in the prepareForSegue class method.

To access it, over-ride the method in the calling view controller like this:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // The Storyboard Segue is named popover in this case:
    if ([segue.identifier compare:@"popover"] == NSOrderedSame) {
        // segue.popoverController is only present in popover segue's
        // self.seguePopoverController is a UIPopoverController * property.
        self.seguePopoverController = segue.popoverController;
    }
}

Then you can dismiss it in the usual way.

like image 32
lnafziger Avatar answered Oct 18 '22 02:10

lnafziger