Disable UIBarButtonItem when popover is dismissed - ios

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

Related

Show dynamic result in a UIPopoverController

I can't set data inside the viewController "searchController" managed by a UIPopoverController:
in viewDidLoad i have:
searchController = [[PopOverSearchController alloc] initWithNibName:#"PopOverSearchController" bundle:nil];
popoverController = [[UIPopoverController alloc] initWithContentViewController:searchController];
I do a method for call this popover that work fine:
if ([popoverController isPopoverVisible]) {
[popoverController dismissPopoverAnimated:YES];
} else {
searchController.data = data;
[searchController.tableResult reloadData];
CGRect popRect = CGRectMake(self.searchBar.frame.origin.x,
self.searchBar.frame.origin.y +15,
self.searchBar.frame.size.width,
self.searchBar.frame.size.height);
[popoverController presentPopoverFromRect:popRect
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}
[searchController.tableResult reloadData]; was not called: the popup appear (above the search bar )but with an empty table

How to dismiss a popover with a navigation controller?

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.

Displaying WEPopover from UIButton instead of UIBarButtonItem

I am using WEPopover in my app to pop up a popover controller containg some buttons,it works when i put wepopover controller action in tabbarIteam but i need to get popover when i click UIButton.How to do this this is my barbuttonitem code for displaying popover.
-(IBAction)_clickbtnAccount:(id)sender
{
if (!self.popoverController)
{
UIViewController *contentViewController = [[pageAccount alloc]initWithNibName:#"pageAccount" bundle:nil];
self.popoverController = [[[popoverClass alloc] initWithContentViewController:contentViewController] autorelease];
self.popoverController.delegate = self;
self.popoverController.passthroughViews = [NSArray arrayWithObject:self.navigationController.navigationBar];
[self.popoverController presentPopoverFromBarButtonItem:sender
permittedArrowDirections:(UIPopoverArrowDirectionUp|UIPopoverArrowDirectionDown)
animated:YES];
[contentViewController release];
}
else
{
[self.popoverController dismissPopoverAnimated:YES];
self.popoverController = nil;
}
}
-(IBAction)_clickbtnAccount:(id)sender
{
if (!self.popoverController)
{
UIButton *senderButton = (UIButton *)sender;
[self.popoverController presentPopoverFromRect:[senderButton frame]
inView:#"pageAccount"
permittedArrowDirections:(UIPopoverArrowDirectionUp|UIPopoverArrowDirectionDown)
animated:YES];
}
else
{
[self.popoverController dismissPopoverAnimated:YES];
self.popoverController = nil;
}
}
So you don't want to display a WEPopoverfrom an UIBarButtonItem but from an UIButton, right?!
Just use
- (void)presentPopoverFromRect:(CGRect)rect
inView:(UIView *)view
permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections
animated:(BOOL)animated;
instead of
- (void)presentPopoverFromBarButtonItem:(UIBarButtonItem *)item
permittedArrowDirections:(UIPopoverArrowDirection)arrowDirections
animated:(BOOL)animated;
and pass in the rect of your UIButton.
Taking your code as an example:
-(IBAction)_clickbtnAccount:(id)sender
{
if (!self.popoverController) {
UIViewController *contentViewController = [[pageAccount alloc]initWithNibName:#"pageAccount" bundle:nil];
self.popoverController = [[[popoverClass alloc] initWithContentViewController:contentViewController] autorelease];
self.popoverController.delegate = self;
self.popoverController.passthroughViews = [NSArray arrayWithObject:self.navigationController.navigationBar];
UIButton *senderButton = (UIButton *)sender;
[self.popoverController presentPopoverFromRect:[senderButton frame]
inView:self.view
permittedArrowDirections:(UIPopoverArrowDirectionUp|UIPopoverArrowDirectionDown)
animated:YES];
[contentViewController release];
} else {
[self.popoverController dismissPopoverAnimated:YES];
self.popoverController = nil;
}
}
WEPopover is basically used to show multiple options inside a popover with much control using UITableview.
This is how i use WEPopOver to show popup on a button click
-(void)showPopOver:(id)sender{
if (self.popoverController) {
[self.popoverController dismissPopoverAnimated:YES];
self.popoverController = nil;
}
PopOverTable *contentViewController = [[PopOverTable alloc] initWithStyle:UITableViewStylePlain];
contentViewController.delegatePopoverItemSelectedDelegate=self;
rectForPopover = [self.view convertRect:btn.bounds fromView:btn];
self.popoverController = [[[popoverClass alloc] initWithContentViewController:contentViewController] autorelease];
if ([self.popoverController respondsToSelector:#selector(setContainerViewProperties:)]) {
[self.popoverController setContainerViewProperties:[self improvedContainerViewProperties]];
}
self.popoverController.delegate = self;
[self.popoverController presentPopoverFromRect:rectForPopover
inView: self.view
permittedArrowDirections:(UIPopoverArrowDirectionAny)
animated:YES];
}
With the accepted solution I get rotation issues for the WEPopover under iOS 7: Basically it was pointing to a custom button in the UIBarButtonItem on the left of the navigation bar but on rotation the pop up moves to the right side of the screen and stays there on further rotations.

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