How to dismiss a popover with a navigation controller? - ios

I have an app which is divided in four views, when I tap a view the app shows a popover and that popover has a navigation controller. I can navigate between view and the data is shows correctly. But when I am in the last view and I tap a row, the popover don't dismiss (I want in didSelectRowAtIndexPath).
How could do it?
I tried in this way, I created a method that dismiss the popover and I call this method en didSelectRowAtIndexPath, but did not works.
This is the method in the main ViewController
-(IBAction)mostrarTabla:(id)sender
{
// Popover that shows the table
UIPopoverController *popover;
// RootViewController is the first view
RootViewController *rootViewController = [[RootViewController alloc] init];
// With a nav bar
UINavigationController *navBar = [[UINavigationController alloc] initWithRootViewController:rootViewController];
[rootViewController release];
// Popover customitation
navBar.contentSizeForViewInPopover = CGSizeMake(20.0f, 20.0f);
popover = [[UIPopoverController alloc] initWithContentViewController:navBar];
[navBar release];
popover.delegate = self;
popover.popoverContentSize = CGSizeMake(320.0f, 832.0f);
// PopOver is shows in the view 1
[popover presentPopoverFromRect:CGRectMake(100.0f, 10.0f, 20.0f, 20.0f) inView:_view1 permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
I create a method in this View Controller
-(void)hidePopover
{
[self.popOver dismissPopoverAnimated:YES];
}
And in the last view I used the method but did not works
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ViewController *grafica = [[ViewController alloc] init];
self.indicadorId = [[self.arrayId objectAtIndex:indexPath.row] integerValue];
DataIndicador *datos =[[DataIndicador alloc] init];
datos.idIndicador = self.indicadorId;
[datos release];
[grafica hidePopover];
}
In the last view I want that the popover returns to its view and shows the data (a chart)
Thanks

The grafica instant of the ViewController is not the same as the whatever instant of VieController that was originally presented the popover.

Related

Disable UIBarButtonItem when popover is dismissed

I am new in iOS development and I am trying to show a popover when tap a barButtomItem. So far I have this:
-(IBAction)shareButtonPressed :(id)sender{
UIViewController *popoverViewController = [[UIViewController alloc] initWithNibName:#"ShareOptionsViewController" bundle:nil];
popoverViewController.contentSizeForViewInPopover = CGSizeMake(319, 422);
self.popoverController = [[UIPopoverController alloc] initWithContentViewController:popoverViewController];
[self.popoverController presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:NO];
}
This code works and when I tap the correct button, the popover is showed. The problem is when the popOver is showed, if I tap again the button, the app crashes. I know is because it is trying to alloc a variable that is already created. I think the solution should be disable the button when the popover loads but I don't know how to activate again once the popover is dismissed.
Am I right? How can I enable the button when the popOver is dismissed?
First you should disabled the button in your shareButtonPressed method.
-(IBAction)shareButtonPressed :(id)sender{
UIViewController *popoverViewController = [[UIViewController alloc] initWithNibName:#"ShareOptionsViewController" bundle:nil];
popoverViewController.contentSizeForViewInPopover = CGSizeMake(319, 422);
self.popoverController = [[UIPopoverController alloc] initWithContentViewController:popoverViewController];
[self.myButton setEnabled:NO];
[self.popoverController presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:NO];
}
Then you make your view controller comply with the UIPopoverControllerDelegate protocol. After that you implement the popoverControllerDidDismissPopover method.
-(void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
{
if (!self.myButton.enabled) // Just to make sure the button is disabled.
[self.myButton setEnabled:YES];
}
Just check if instance is already created.
-(IBAction)shareButtonPressed:(id)sender
{
if (self.popoverController == nil) {
self.popoverController = alloc/init...;
[_popoverController present...];
} else {
if (self.popoverController.popoverVisible)
[self.popoverController dismissPopoverAnimated:YES];
self.popoverController = nil;
}
}
There is a possibility, it will be garbage collected before animation completes, yielding invalid user experience. Then, if possible, I would pre-create the instance in viewDidLoad or contructor or so and then just present and dismiss as needed, checking visible property.
Look at this "event --> responsible" list:
1) Button pressed --> MainViewController - IBAction
2) Popover shown --> MainViewController - IBAction
3) Button disabled --> MainViewController - IBAction
4) Popover dissmis --> popoverDelegate - popoverControllerDidDismissPopover
5) Button enabled --> popoverDelegate - popoverControllerDidDismissPopover
So, if the delegate of your popover is the MainViewController, you would have access to the button, if it is a different class you'll probably have to set up a protocol in order to enable the button back.
Tell me if you need any further explanations...
Just modify your code like this...
-(IBAction)shareButtonPressed :(id)sender{
UIViewController *popoverViewController = [[UIViewController alloc] initWithNibName:#"ShareOptionsViewController" bundle:nil];
popoverViewController.contentSizeForViewInPopover = CGSizeMake(319, 422);
if(self.popoverController)
{
[self.popovercontroller dismissPopoverAnimated:YES];
self.popovercontroller = nil;
}
self.popoverController = [[UIPopoverController alloc] initWithContentViewController:popoverViewController];
[self.popoverController presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:NO];
}
you can detect if the popover is shown and dismissed:
- (IBAction)shareButtonPressed :(id)sender{
if (self.popoverController) {
[self.popoverController dismissPopoverAnimated:YES];
self.popoverController = nil;
} else {
UIViewController *popoverViewController = [[UIViewController alloc] initWithNibName:#"ShareOptionsViewController" bundle:nil];
popoverViewController.contentSizeForViewInPopover = CGSizeMake(319, 422);
self.popoverController = [[UIPopoverController alloc] initWithContentViewController:popoverViewController];
[self.popoverController presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:NO];
}
}
or if you just want to disable the button:
- (IBAction)shareButtonPressed :(id)sender{
...
UIButton *button = (UIButton *)sender;
button.enabled = NO;
}
but in this case you will have to detect when the user close the popOver to enable the button again. You can do this adopting the UIPopoverController delegate (see documentation) in your class

Keep popovercontentsize constant for all views in navigationcontroller

When I pass my UINavigationController to UIPopOver and set its popOverContentSize property, it remains in effect for only first view. When I navigate to next view, the popOverContent size again expands to full view which is unwanted. How can I restrict the constant size of popOver for all views in navigation controller?
- (void)selectTextStyle:(id)sender {
DJTextStyleMasterViewController *textStyle = [[DJTextStyleMasterViewController alloc] init];
self.navController = [[UINavigationController alloc] initWithRootViewController:textStyle];
UIPopoverController *popOver = [[UIPopoverController alloc]
initWithContentViewController:self.navController];
[popOver setDelegate:self];
[popOver setPopoverContentSize:CGSizeMake(320, 400)];
[popOver presentPopoverFromBarButtonItem:self.textStyleButton permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
[textStyle release];
}
within the first view controller in the popover controller you could use this method:
[self setContentSizeForViewInPopover:CGSizeMake(320, 400)];
Then the view of the popover (if it isn't manually modified) should be the same also for the next view controller.

navigationItem added to ABPersonViewController disappears when app resumed

I created an ABPersonViewController and added a done button:
ABRecordRef rec = ABAddressBookGetPersonWithRecordID(addrBook, recordID);
if (rec) {
ABPersonViewController* personController = [[[ABPersonViewController alloc] init] autorelease];
personController.displayedPerson = rec;
personController.personViewDelegate = self;
personController.allowsEditing = NO;
UIBarButtonItem* doneButton = [[[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target: self
action: #selector(dismissModalView:)] autorelease];
UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:personController] autorelease];
[self.appViewController presentModalViewController:navController animated: YES];
// this needs to be AFTER presentModal, if not it does not show up (iOS 4 regression: workaround)
personController.navigationItem.rightBarButtonItem = doneButton;
I should have been suspicious that it had to be added AFTER the view was presented.
This worked until the app was sent to the background with this view active. When the app was restored the done button was no longer there. I've tried many ways to add this Done button but could never get it to remain through an app pause.
Here is the solution. Create an empty UIViewController in front of the ABPersonViewController. This will cause the ABPersonViewController to have a back button rather than the created done button. Override ABPersonViewController (DisplayContactViewController below) so you can implement viewDidDisappear. This will be called when the user presses the back button. In viewDidDisappear you can take down the entire navigation stack (including the empty View controller) and get back to your original view.
DisplayContactViewController* personController = [[[DisplayContactViewController alloc] init] autorelease]; //
personController.displayedPerson = rec; // the ABPersonRecord to display
personController.personViewDelegate = self;
personController.allowsEditing = NO;
personController.contactsPlugin = self; //this is my hook so I can dismiss the picker view later
// create this so DisplayContactViewController will have a "back" button.
UIViewController* parentController = [[[UIViewController alloc] init] autorelease];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:parentController];
[navController pushViewController:personController animated:YES];
[self.appViewController presentModalViewController:navController animated: YES];
Here is DisplayContactViewController viewDidDisappear.
[super viewDidDisappear: animated];
[self.contactsPlugin.appViewController dismissModalViewControllerAnimated:NO];

Releasing a popover which takes great amount of memory

I am using a popover view to present a large amount of flags of which the your can select.
There is something wrong with my code since soon after I open this popover memory is not released (the viewcontroller "flagsViewController" is ok and clean, it does init and release each and every item inside of it.
What am I doing wrong? How can I free memory as soon as the popover is closed?
-(void)presentFlags
{
[self.popoverController dismissPopoverAnimated:YES];
FlagsViewController *controller = [[FlagsViewController alloc]
initWithNibName:#"FlagsViewController"
bundle:[NSBundle mainBundle]] ;
UINavigationController *container = [[UINavigationController alloc] initWithRootViewController:controller];
UISegmentedControl *ctrl = [[UISegmentedControl alloc] initWithItems:segmentedItems];
ctrl.frame = CGRectMake(0, 6, 500, 30);
[ctrl addTarget:self action:#selector(changeSeg:) forControlEvents:UIControlEventValueChanged];
ctrl.segmentedControlStyle = UISegmentedControlStyleBar;
//ctrl.momentary = YES;
ctrl.tintColor = [UIColor darkGrayColor];
UIImage *theImage = [UIImage imageNamed:#"highlight_country.png"];
[ctrl setImage:theImage forSegmentAtIndex:0];
[container.navigationBar addSubview:ctrl];
[ctrl release];
//
//create a popover controller
self.popoverController = [[[UIPopoverController alloc]
initWithContentViewController:container] autorelease];
[container release];
[popoverController setPopoverContentSize:CGSizeMake(500, 600)];
//present the popover view non-modal with a
//refrence to the button pressed within the current view
[popoverController presentPopoverFromRect:CGRectMake(popoverArrowPossition, 0.0, 0.0, 52.0) inView:super.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
[controller release];
}
Working with the UIPopoverController has been pretty difficult but I solved this problem by doing the following setting the Delegate of the Popover Controller to self (popoverController.delegate = self) and adding the UIPopoverControllerDelegate Protocol to your Class Header
Next, I implemented the - (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController delegate method and here I released the popoverController and set it to nil.
- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController {
[self.popoverController release];
self.popoverController = nil;
}
Please note: This delegate method won't be called if you dismiss the popover via code (i.e. using dismissPopoverAnimated), it'll only be called if this User dismisses it by tapping outside the popover etc.

Navigation Controller in popover

I am a total newbie in the ipad app development.
I am interested in creating an application where i have a popover showing a tableview with list of items. Then i select an item and the view drills to another tableview consisting of another list of items and a navigate back button as well.
the level to which i would be drilling down is dynamic.
Please guide me with appropriate resources to help me solve the problem.
I did it before and it works well!
Just assign this function to your button (perhaps an UIBarButtonItem):
UIPopoverController *popover;
bool isPopoverOpen = false;
-(void)openPopover{
if(!isPopoverOpen){
FirstViewController *firstViewCtrl = [[PartsViewCtrl alloc] init];
UINavigationController *navbar = [[UINavigationController alloc] initWithRootViewController:firstViewCtrl];
[firstViewCtrl release];
navbar.contentSizeForViewInPopover = CGSizeMake(TABLE_WIDTH, TABLE_HEIGHT);
popover = [[UIPopoverController alloc] initWithContentViewController:navbar];
[navbar release];
popover.delegate = self;
popover.popoverContentSize = CGSizeMake(TABLE_WIDTH, TABLE_HEIGHT);
[popoverOnPartsView presentPopoverFromBarButtonItem:barButtonItem permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
isPopoverOpen = true;
}else{
[popover dismissPopoverAnimated:YES];
[popover release];
isPopoverOpen = false;
}
}
And implement this function to FirstViewController which has an UITableView:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
SecondViewController *secondViewController = [[SecondViewController alloc] init];
[self.navigationController pushViewController:secondViewController animated:YES];
[secondViewController release];
}
Now you can add an UITableView to SecondViewController, Too. And use this scenario for other tables!
I hope it works for you!
When you create the popover, you just need to allocate a UINavigationController and use this to manage the view hierarchy within the popover itself. A quick web search revealed this tutorial which covers the things you need to know.
I also meant to add that you should get up to speed with Objective-C and iOS development in general. Don't try and blindly use things you've found on the net without understanding what you're actually doing :)
Do the following steps
1)In the action of button (by clicking on that button pop over should appear) write the code
[here PopOverContentViewController is a viewController where i have table view and several list of items which should be displayed when the pop over arrives]
- (IBAction)callPopOver:(id)sender
{
UIButton *button = (UIButton*)sender;
PopOverContentViewController1 *popOverContent = [[PopOverContentViewController1 alloc]initWithNibName:#"PopOverContentViewController1" bundle:nil];
UINavigationController *navbar = [[UINavigationController alloc] initWithRootViewController:popOverContent];
navbar.contentSizeForViewInPopover = CGSizeMake(266, 200);
popover = [[UIPopoverController alloc] initWithContentViewController:navbar];
popover.delegate = self;
[popover presentPopoverFromRect:CGRectMake(button.frame.size.width / 2, button.frame.size.height / 1, 1, 1) inView:button permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
[popover setPopoverContentSize:CGSizeMake(266, 200) animated:YES];
[popUpContent release];
}
2)now to change the table view on clicking on any of the rows type this code in PopOverViewController.m
[here PopOverViewController2 is the ViewController where we have the next table view to be displayed]
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
PopOverViewController2 *secondViewController = [[PopOverViewController2 alloc] init];
[self.navigationController pushViewController:secondViewController animated:YES];
[secondViewController release];
}
3)to avoid the change in size of popover while navigation write the following code in viewDidLoad of both view controllers (ie PopOverContentViewController1 and PopOverContentViewController2)
- (void)viewDidLoad
{
[super viewDidLoad];
[self setContentSizeForViewInPopover:CGSizeMake(266, 200)];
}

Resources