dismiss UIPopoverController (if visible) after tapping a UIBarButtonItem - uibarbuttonitem

I'm trying to dismiss any currently visible UIPopoverControllers if/when another UIBarButtonItem is tapped as seen on Pages for the iPad when tapping between Styles/Media/Tools etc.
I've done this, but it's too specific. Looking for something generic.
if ([popoverController isPopoverVisisble]) {
[popoverController dismissPopoverAnimated:YES];
}
Thanks!

Did you set the passthroughViews property of the popover controller? If you do this, then taps outside the popover will not cause the popover to automatically dismiss, but will instead be sent to the views in that array. You should be able to add the UIBarButtonItem to this array, and then dismiss the popover in that handler.

randallmeadows answer will NOT work. UIBarButtonItem is not descendant of UIView, which means you cannot add it to passthroughViews.
The only solution I found for now is to create UIBarButtonItem with custom UIButton using
UIBarButtonItem *b = [[UIBarButtonItem alloc] initWithCustomView:button]
and then
popoverController.passthroughViews = [NSArray arrayWithObject:b.customView];
But be prepared that you'll loose all the styling - you cannot create UIButton that looks like UIBarButtoItem too easily.

[popoverController presentPopoverFromBarButtonItem:sender permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
popoverController.passthroughViews = #[];
Works for me

Related

How to I launch a view controller from a tap gesture

Apologies if this is a basic question but I am new to Xcode and have a storyboard app and in the storyboard (with no segue) I have a view controller with an embedded map view.
On the storyboard screen I have an image with a tap gesture linked, I have tested the tap and it works (NSLog) but I want to know how to launch my mapview view controller and also zoom to an x&y.
My code currently has
-(IBAction)handleMapTap:(UIGestureRecognizer *)sender {
NSLog(#"Tapped");
}
& I have tried;
MMMapViewController *mapViewController = [[MMMapViewController alloc] initWithNibName:#"MapView" bundle:nil];
[self.navigationController pushViewController:mapViewController animated:YES];
My view controller has a class set as MMMapViewController I have given the view controller a storyboard id of MapView (if it's required?).
I've read a lot of stackoverflow articles but can't seem to find an answer. If anyone can help I would be really grateful.
-(IBAction)handleMapTap:(UIGestureRecognizer *)sender
{
MMMapViewController *mapViewController = [[MMMapViewController alloc] initWithNibName:#"MapView" bundle:nil];
//[self.navigationController pushViewController:mapViewController animated:YES];
[self presentModalViewController:mapViewController animated:YES];
[mapViewController release];
}
It would probably help to know what self is, if it is indeed a UIViewController, then
I would make sure that self.navigationController is not nil.
You actually have the right code, as far as I can tell, but depending on your scenario, you could get away with presenting the mapView as a modal view controller.

Xcode change image on button that is not sender

I am trying to change a image of a button that is not the senders, I have tried to link the code to the buttons and it seems not to work
I tried to link the 3 buttons to the -(IBAction)Button1:(id)sender; it still does not work.
.h
-(IBAction)Button1:(id)sender;
-(IBAction)ButtonUn1:(id)sender;
-(IBAction)ButtonDef1:(id)sender;
.m
-(IBAction)Button1:(id)sender
{
UIImage *btnImage1 = [UIImage imageNamed:#"button_Not_At_all_R.png"];
[sender setImage:btnImage1 forState:UIControlStateNormal];
UIImage *btnImage2 = [UIImage imageNamed:#"Button_Unsure.png"];
UIImage *btnImage3 = [UIImage imageNamed:#"Button_Definitely.png"];
[ButtonUn1 setImage:btnImage2 forState:UIControlStateNormal];
[ButoonDef1 setImage:btnImage3 forState:UIControlStateNormal];
}
Thanks for any help.
You need to create an IBOutlet for your button and link it to access it directly:
IBOutlet UIButton* buttonToChangePicture;
The IBAction ist only used to access an event.
Edit:
Another option is to use viewWithTag.
UIButton* button = (UIButton*)[myView viewWithTag:555]
You need to set a unique tag for your button first (555 in my example)
There is no other way to access another button in an IBAction

How to add the Navigation Bar's view to a PopOver's PassThroughViews?

I have a PopoverController view that allows a user to download a file. On button press, the popOver view will expand in size, display download status, and the main view controller will be obscured by an unhidden "cover" view that has been added to the PopoverController's "passThroughViews" property so that the user can not accidentally dismiss the pop over while the file is downloading.
My problem is that, in storyboards, my main viewController is embedded in a Navigation Controller. I can't seem to cover the navigation controller's bar with a view in the storyboard, and if the user presses anywhere on the navigation bar then the popover will disappear and the user will lose the download's progress bar.
How do I either cover up the navigation bar with my "cover" view, or how do I add the navigation bar's view to my popOverController's passThroughViews?
Opening the Popover from the main viewController:
- (IBAction)openDataOptionsPopOver:(id)sender
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
PopOverViewController *optionsWindow = [storyboard instantiateViewControllerWithIdentifier:#"dataOptions"];
self.popUp = [[UIPopoverController alloc] initWithContentViewController:optionsWindow];
[self.popUp setDelegate:self];
[nextNavButton setEnabled:NO]; //Disabling barButtonItem on the navigationController
optionsWindow.containerPopOver = self.popUp; //Pointer to the popover, to resize it later.
optionsWindow.coverView = self.coverView; //Pointer to the coverView, to (un)hide later
[popUp presentPopoverFromRect:[sender frame] inView:[sender superview] permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES];
}
Setting the passThroughViews property inside of the PopoverViewController:
//Expands the popOver on press of "refreshFileButton" to display progressView
-(void) explodeWindow
{
//setting self.navigationController.view and ...visibleViewController.view here didn't seem to work ...
[containerPopOver setPassthroughViews:[NSArray arrayWithObjects:coverView, nil]];
[containerPopOver setPopoverContentSize:CGSizeMake(600, 400) animated:YES];
[titleBarItem setTitle:#"Downloading File. Please Wait ..."];
[refreshFileButton setHidden:YES];
[progressView setHidden:NO];
[downloadLabel setHidden:NO];
[coverView setHidden:NO];
[progressView setProgress:0.0 animated:NO];
}
I've tried adding self.navigationController.view to passThroughViews with no success--it actually turns out to be a null pointer. And I can't seem to place a UIView at any level in storyboards that will cover all my controls without obscuring the popOver. What am I missing here? And thanks for reading.
Edit:
As Aglaia points out below out, implementing the following, and avoiding passThroughViews, is probably the best way to do this.
- (BOOL)popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController
{
//Don't dismiss our popover when the view covering our controls is present
if([coverView isHidden]){
return YES;
}else{
return NO;
}
}
Maybe there is something I am missing, but why don′t you just implement a new view controller with its navigation bar set to none and present it modally on button press? Then when the download is finished you just dismiss the view controller.
If you want the user to see the underlying view you can use a UIAlertView instead.
Alternatively set you view controller as the delegate of the popover controller and forbid the user to dismiss your popover on touch outside through
- (BOOL) popoverControllerShouldDismissPopover:(UIPopoverController *)popoverController
{
return NO;
}
Then when you want to dismiss it call dismissPopoverAnimated:
to cover the whole screen including navigation bar:
[myView setFrame:[[UIScreen mainScreen] bounds];
[self.navigationController.view addSubview:myView];

Show NSPopover from NSToolbarItem Button

I want to show an NSPopover from an NSToolbarItem button in my toolbar.
(i.e. positioned below the button).
Ideally, I want to pass the NSView of the button to the popover to position it.
My question is, how do I get the NSView of the NSToolbarItem?
[toolbarbutton view] always returns nil.
The answer appears to be in the video for the 2011 WWDC Session 113, "Full Screen and Aqua Changes." Basically, put an NSButton inside the NSToolbaritem and use the view of that.
A blog post is here: http://www.yellowfield.co.uk/blog/?p=33, and a sample project is on github at http://github.com/tevendale/ToolbarPopover
All in the sprit of http://xkcd.com/979!
You can send the action directly from the NSButton enclosed in the NSToolbarItem (which is what you should generally do anyways, consider segmented controls, where each segment has its own target/action), and that will do the trick.
Instead of getting the view from the IBAction sender, connect an IBOutlet directly to the toolbar item and use that to get the relative view:
In your header file:
#property (weak) IBOutlet NSToolbarItem *theToolbarItem;
#property (weak) IBOutlet NSPopover *thePopover;
In your implementation file, to show the popover:
[self.thePopover showRelativeToRect:[[self.theToolbarItem view] bounds] ofView:[self.theToolbarItem view] preferredEdge:NSMinYEdge];
This will also work for showing popups from menu item selections inside a toolbar item.
While I did achieve that the Popover was shown using the approach mentioned by Stuart Tevendale, I did run into problems when I tried to validate (enable / disable) the NSToolbarItems using the NSToolbarDelegate:
-(BOOL)validateToolbarItem:(NSToolbarItem *)toolbarItem {
BOOL enable = YES;
NSString *identifier = [toolbarItem itemIdentifier];
// This does never get called because I am using a button inside a custom `NSToolbarItem`
if ([identifier isEqualToString:#"Popover"]) {
return [self someValidationMechanism];
}
// For this the validation works when I am using a standard `NSToolbarItem`
else if ([identifier isEqualToString:#"StandardToolbarItem"]){
return [self someOtherValidationMechanism];
}
return enable;
}
So I would advise not to display a Popover from NSToolbarItem. An alternative might be to show a Page Sheet: How to show a NSPanel as a sheet

Calling function from popover

Alright, so I made a popover from my main view and all that good stuff. But I want to have my popover call an action in my main view when a button within the popover is pressed.
MainView *mainView = [[MainView alloc] initWithNibName:#"MainView" bundle:nil];
[mainView doStuff];
The "dostuff" function changes some elements within the view. For example, the color of the toolbar is supposed to be changed. I've put a print command and the print command executes. But for some reason, the toolbar won't change color.
I've imported the header of MainView into the popover.
I did an #class thingy for MainView in my popover.
doStuff is declared in MainView's header.
The IBOutlets are declared too, and connected.
Any ideas?
Well its disappointing that we have no direct method that can be used to check in which view (view controller) the popover is shown. The thing that I am doing in tabbased application is:
New_iPadAppDelegate *appDel = (New_iPadAppDelegate *)[[UIApplication sharedApplication] delegate];
NSArray *viewConts = [(UINavigationController *)[[appDel tabBarController] selectedViewController] viewControllers];
MainViewController *viewController = (MainViewController *)[viewConts lastObject];
if([[viewController popoverController] isPopoverVisible]){
[viewController doStuff];
}
Hope this helps,
I know this is not the best way, hoping apple thinks about this issue, or if somebody has devised a work around.
Thanks,
Madhup

Resources