views:

3910

answers:

7

Using a split view on the iPad, I have the following code:

- (void)splitViewController: (UISplitViewController*)svc willHideViewController:(UIViewController *)aViewController withBarButtonItem:(UIBarButtonItem*)barButtonItem forPopoverController:(UIPopoverController*)pc {

barButtonItem.title = @"Categories";
NSMutableArray *items = [[toolbar items] mutableCopy];
[items insertObject:barButtonItem atIndex:0];
[toolbar setItems:items animated:YES];
[items release];
self.popoverController = pc;

}

This works well to show the popover when the button is pressed. However, I'd also like to have the popover dismiss if the button is pressed while it is already open to follow good guidelines. How would I go about doing this? (i.e. if the user repeatedly clicks this button, the popover should come and hide every other hit.)

A: 

You could try the below

if(![popoverController isPopoverVisible]){
   // Show popover
}
else{
   // close popover
   [popoverController dismissPopoverAnimated:YES];
}
Podcaster123
+1  A: 

This is a lot easier because the popoverController is a property. Makes it easier to reference.

if ([self.popoverController isPopoverVisible]) {
    //using the setters and getters "goes thru the proper channels" when accessing objects
    [self.popoverController dismissPopoverAnimated:YES];
} else {
    UIPopoverController *pc = [[UIPopoverController alloc] initWithContentViewController:YOUR_VIEW_CONTROLLER];
    self.popoverController = pc;
    [pc release];

    //get the button instance you set on the toolbar
    UIBarButtonItem *categoryButton = [[toolbar items] objectAtIndex:0];
    [self.popoverController presentPopoverFromBarButtonItem:categoryButton permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}

I actually just realized that you're referring to the code inside the Delegate method for displaying the viewController at index:0 of your splitView. This answer doesn't necessarily apply to that, but does apply to any other time you're accessing and creating popoverControllers on the iPad. Without checking if a popover is visible first, you will either crash, or open several popovers.

Thanks for your time.

JustinXXVII
I'm trying to create a popover on my iPad not from a toolbar and then dismiss it from a button in it. I just realized now that the code I pasted is wrong.
joshholat
A: 

the code should be

-(IBAction)addCategory:(id)sender {

AddCategoryViewController* content = [[AddCategoryViewController alloc] init];
UIPopoverController* aPopover = [[UIPopoverController alloc]
                                 initWithContentViewController:content];
aPopover.delegate = self;

// Store the popover in a custom property for later use.
self.addCategoryPopover = aPopover;
addCategoryPopover.delegate = self;
[aPopover release];
[content release];

[addCategoryPopover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];

/*AddCategoryViewController *addCategoryViewController = [[AddCategoryViewController alloc] init];

UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:AddCategoryViewController];
self.addCategoryViewController = popover;
addCategoryViewController.delegate = self;*/

/*if (addCategoryPopover.popoverVisible == NO) {
    addCategoryPopover = [[UIPopoverController alloc] initWithContentViewController:[[AddCategoryViewController alloc] init]];
    addCategoryPopover.delegate = self;
    addCategoryPopover.popoverContentSize = CGSizeMake(300, 100);       
    [addCategoryPopover presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}*/

}

to show the popover in rootviewcontroller.m and

-(IBAction)saveAddCategory:(id)sender {
rootViewController = [[RootViewController alloc] init];
    [rootViewController dismissPopover];
//[rootViewController.addCategoryPopover dismissPopoverAnimated:YES];

/*if (rootViewController == nil)
    rootViewController = [[RootViewController alloc] init];

[rootViewController.addCategoryPopover dismissPopoverAnimated:YES];
[rootViewController dismissPopover];*/

}

to try and dismiss it from another class. the dismiss popover function looks like:

-(void)dismissPopover {
NSLog(@"hey");
if ([self.addCategoryPopover isPopoverVisible])
    [self.addCategoryPopover dismissPopoverAnimated:YES];

if (addCategoryPopover.popoverVisible == YES) {
    [addCategoryPopover dismissPopoverAnimated:YES];
}

}

joshholat
A: 

Apple's HIG says there should not be an explicit dismiss button inside a popover, but to do what you're asking, you have two options.

1) post an NSNotification

OR

2) drill down into your view hierarchy until you have the popover instance

1) in whichever view you are presenting the popover in, in the viewDidLoad method:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dismissThePopover) name:@"popoverShouldDismiss" object:nil];

create a method called "dismissThePopover" and in the dealloc method, removeObserver

-(void)dismissThePopover {
    [self.popoverController dismissPopoverAnimated:YES];
}

-(void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

In your popoverController "dismiss" button, enter this line:

[[NSNotificationCenter defaultCenter] postNotificationName:@"popoverShouldDismiss" object:nil];

Doing that sends a notification to the app, and since you've registered your other view controller to listen for it, whenever it sees that notification it calls the selector you specify, in this case, dismissThePopover.

2) drill down into your view hierarchy to find self.popoverController

check this out, yours will be different, surely, but the overall idea is the same. Start at your AppDelegate, move into the first viewcontroller, move into subviews until you get to your self.popoverController object.

MyAppDelegate *appDelegate = [[UIApplication sharedApplication]delegate];
//appDelegate instance, in this case it's the .m file for your ApplicationDelegate

UISplitViewController *svc = appDelegate.splitViewController;
//In this case the first view inside the appDelegate is a SplitView, svc

UINavigationController *navc = [[svc viewControllers]objectAtIndex:0];
//a navigationController is at index:0 in the SplitView hierarchy. DetailView is at index:1

NSArray *vcs = [navc viewControllers];
//vcs is the array of different viewcontrollers inside the Navigation stack for nvc

iPadRootViewController *rootView = [vcs objectAtIndex:0];
//declare the rootView, which is the .m file that is at index:0 of the view array

UIPopoverController *pc = [rootView popoverController];
//HERE WE GO!!! popoverController is a property of iPadRootViewController's instance rootView, hereby referred to as pc.

[pc dismissPopoverAnimated:YES];
//bye bye, popoverController!

Hope this helps

JustinXXVII
Thanks, I've used notifications before, and I'll definitely try that method out this time once again.
joshholat
A: 

If you are using the default Split-View Controller setup, than the barbutton that is created displays a popover of your rootviewcontroller.

If you want to make sure you don't have multiple pop-ups on at once, you can simply dismiss pop-ups whenever your RootViewController will appear. Here's the code I used to solve this problem:

- (void)viewWillAppear:(BOOL)animated {
if([self.popover isPopOverVisible]) {
[self.popover dismissPopoverAnimated: YES];
}
[super viewWillAppear:YES];
}
Smorpheus
+3  A: 

When splitViewController display popover, below method will be called. Just check if not nil, then dismiss it :)

- (void)splitViewController:(UISplitViewController*)svc popoverController:(UIPopoverController*)pc willPresentViewController:(UIViewController *)aViewController{
  if (popoverController != nil) {
     [popoverController dismissPopoverAnimated:YES];
  }
}
sunnycmf
Chris Miles
A: 

Apple says: Avoid providing a “dismiss popover” button. A popover should close automatically when its presence is no longer necessary. See: iPad HIG

dombesz