I have a problem dismissing a popover that was launched from the navigationItem of a UINavigationController. It seems that the navigation item which is inserted by the UINavigationController does not trigger dismissal of the UIPopoverController. Usually, when you tap outside a popover, it is dimissed. But when you tap on the navigation item, the popover is not dismissed. Worse, if you tap the button which triggers the popover, you'll get a second instance of the popover.
All of this is done using storyboards:
- Create a view, embed it into a UINavigationView so it gets a navigationItem on the top.
- Put a UIBarButtonItem into the navigationItem (left or right, doesn't matter for the initial view on the navigation stack).
- Define another view, and drag a segue from the UIBarButtonItem to this view.
- Set the segue to be popover.
Once the popover is open, I cannot dismiss it by tapping on the navigationItem. I cannot believe this "works as designed", so I suspect I missed out on somthing.
Although my goal is to program as little as possible (that's what storyboards are about, aren't they?), I thought about workarounds: The first workaround that came to my mind was to add a UITapGestureRecognizer to the navigationItem, which would dismiss the popover when it detected a tap on the navigationItem. Unfortunately, the navigationItem seems to not be UIVIew, so it lacks the addGestureRecognizer: method...
EDIT: Adding a UITapGesturerecognizer to self.navigationController.navigationBar is possible, but prevents any tap to reach the UIBarButtonItems on the navigationBar. Yes, I could have expected that.
Thanks a lot for help,
nobi
Here's the complete description for popovers in storyboards. Assuming your controller to appear in the popover is named MyPopupController, do this:
Define a segue from the main scene to the MyPopupController scene, using style Popover.
Add a property to MyPopupController.h
#property (weak, nonatomic) UIPopoverController *popover;
Synthesize the property in MyPopupController.m
#synthesize popover = _popover
In the prepareForSegue:sender: method of the main scene controller, set up the popoverproperty:
UIStoryboardPopoverSegue *ps = (UIStoryboardPopoverSegue *)segue;
MyPopupController *dc = ps.destinationViewController;
dc.popover = ps.popoverController;
In the viewWillAppear: method of MyPopupController, add the following code (don't forget [super viewWillAppear] as well):
self.popover.passThroughViews = nil;
You should be done now.
Thanks to Robert for the basic idea - I just had to find the correct place because presentPopoverFromBarButtonItem is not used when using storyboards. Note that putting (5) into viewDidLoad does not work.
Have fun coding!
https://stackoverflow.com/a/12874772/1455770
after presenting a popover from a bar button item, the popover has had its "passthroughViews" set to include the nav bar, so your taps don't register. Set the passthroughviews to nil straight after you present the popover. ie.
self.myPopoverController presentPopoverFromBarButtonItem:myBarButtonItem permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
self.myPopoverController.passthroughViews = nil;// at this point the myPopoverController has had its pass through views set to include the whole nav bar. remove it.
There might be a better solution than this, but why not only add the UITapGestureRecognizer to the navBar whenever the popover is open? Once you tap the button to open the popover, add the TapGestureRecogniser to the navBar. Once you dismiss the popover, remove the TapGestureRecogniser from the navBar.
I've faced this problem recently and none of the solutions that I've seen around worked for me. Then after some research I've found out a way that works like a charm.
First you need to add the UIStoryboardPopoverSegue to your class.
#property (nonatomic, strong) UIStoryboardPopoverSegue *popoverSegue;
Synthesize it inside of the class implementation:
#synthesize popoverSegue;
Afterwards, inside of the function called by your button when pressed add the following code:
([[popoverSegue popoverController] isPopoverVisible]) ?
[self.popoverSegue.popoverController dismissPopoverAnimated: YES] :
[self performSegueWithIdentifier: #"popSegue" sender:nil];
Now you are almost ready. inside of the method
- (void) prepareForSegue:(UIStoryboard)segue sender:(id)sender add the following code:
if([[segue identifier] isEqualToString:#"popSegue"]){
self.popoverSegue = (UIStoryboardPopoverSegue*) segue;
if(viewPopoverController == nil){
viewController = [[UIViewController alloc] init];
viewPopoverController = [[UIPopoverController alloc] initWithContentViewController:viewController];
}
}
Now every time you press the button it will either show or dismiss your window, the window will also be dismissed if you press outside of the popover. I hope it can help someone.
Related
My question is quite simple but no way to find a simple exemple on internet.
I have a main view controller with buttons and i'd like to display an UIView created with IB when i click on a button, so for exemple:
-ViewController (.h/.m/.xib) is my main interface with a menu button
-MenuView (.h/.m/.xib) is my view that i would like to be displayed as a pop up window over my uiviewcontroller.
So how is it possible to control my MenuView from my viewController ? Is it possible to create it with IB or is it better to make it programmatically? Thank you very much for your help!
I don't know for a way to do this only with interface builder, but the IB can help you. I will do it creating another view controller which contains the view you want to be shown. On your already existing view controller you can create a method i.e:
- (void) show: (id) sender {
UIViewController *theNewController = [TheNewController alloc] initWithNibName: #"TheNewController" bundle:[NSBundle mainBundle]];
[self presentViewController:theNewController animated:YES completion:nil];
}
and link this method, using the IB, to the button actions.(right click on the button in IB, choose the event i.e Touch Down, drag'n drop to the File's Owner). But I recommend you also seeing view controller's apple documentation: http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ModalViewControllers/ModalViewControllers.html
I would like to ask a question.
Now i'm training about iPhone Programming.
I'm just new baby in iOS Programming.
I want to add navigationbar in UIPickerView's upper place.
It's like the UINavigationBar in MainView.
I just want to add on UIPickerView.
and also i want to add Done button in that NavigationBar.
After i touched that done button, my view will back to main view.
How can i do that?
Please answer me if you know.
I hope you understand my question.
Sorry for my bad english.
Thanks you for reading.
All you do is drag a navigation bar on the top of the uipicker. Im assuming your wanting this UIPicker to popup, so just create a view just for the picker, drag in a navigation bar and uipicker into the view, then adjust the size of your view window for the bar and uipicker. THen you just need to hookup the the bar and uipicker to file's owner as delegates. Make sense?
When I understand you correct, you have one navigation controller and want to add to this navigation controller a new UIView with a UIPickerView which comes up after pushing the edit Button and hide when you press done button?
Then I would create a new UIViewController in Interface Builder, add the UIPickerView to this View. Put this in the correct place. In the new view controller add a property of type UIPickerView and connect the IBOutlet of PickerView to the FilesOwners Property. In the Controllers method viewDidLoad you set then for example:
[self.datePicker setHidden: YES];
self.navigationItem.rightBarButtonItem = self.editButtonItem;
This button calls automatically the method setEditiong: on pushing. You can reimplement it for example:
- (void)setEditing:(BOOL)editing animated:(BOOL)animated {
[super setEditing:editing animated:animated];
if (editing) {
[self.datePicker setHidden:NO];
} else {
[self.datePicker setHidden:YES];
}
}
I have a parent view with a hidden button, and a method that unhides that button. That parent view has a modal view in which I need to call the method that hides the button.
ParentViewController.m
- (void)unhideButton {
myButton.hidden = NO;
NSLog(#"Unhide");
}
ModalViewController.m
- (void)levelComplete {
ParentViewController *controller = [[ParentViewController] alloc] init];
[controller unhideButton];
[controller release];
}
The NSLog message Unhide is successfully showing up in the console, but when I dismiss the modal view controller, the button is still hidden. What am I doing wrong?
Modal view controller's have an automatic reference to the view controllers that present using the parentViewController property. So you can directly say,
[self.parentViewController unhideButton];
in the levelComplete method.
But yeah creating a new instance and calling the method on it will not affect the original instance like Ryan said.
Why is the ModalViewController, which is presumably presented by an instance of ParentViewController, instantiating a new ParentViewController? I think what you need to do is pass a reference to the existing ParentViewController to the ModalViewController when you create it, then in ModalViewController it can set the hidden property on the parents button.
If you want to follow good design practices, the ParentViewController needs to delegate the management of its button to the ModalViewController. ParentViewController would conform to a simple protocol, exposing the button, and would set itself as the delegate of the ModalViewController before presenting it.
The problem:
There was an image here, but the link went dead. It shows a UIImagePickerController shown inside a popover, as a view inside of another controller (that is, it's not the root VC of the popover). It sports a Cancel button.
Can this button be killed in a popover? I can remove the button in the ABPeoplePicker*Controller that appears when picking Contacts by editing the private VC's navigation item on the fly, but this one eludes me (no UINavigationControllerDelegate methods are called by the UIIPC).
I think you can change it to something else (not sure about removing) because UIImagePickerController inherits UINavigationController. Then you can get
UINavigationBar *bar = picker.navigationBar;
[bar setHidden:NO];
bar.navigationItem.rightBarButtonItem = doneButton;
in my application the first view is an UIView with a couple of uilabel and an uibutton to do the login.
I would to show an uinavigationcontroller with a table after the login, so with the action of the button.
I know how to set up a working Navigation Controller starting with the Xcode Template but i dont know how to load this as a "Second View"
Any help?
You can add the view of the UINavigationController to the UIWindow and either let it obscure the first view or remove that view from the UIWindow. The navigationController won't have a back button to take you back to the first view (since it's stack doesn't include the first controller), so you'll need a custom button if you want to provide a way back.
- (IBAction) buttonPressed {
myNavigationController = [[UINavigationController alloc] initWithRootViewController:mySecondViewController];
[self.view.window addSubview:myNavigationController.view];
[self.view removeFromSuperview];
}
That's the direct answer to your question, however, if you simply want UINavigationController functionality but don't want to see the UINavigationBar on the first screen - check out:
Hiding the UINavigationBar only for the root UIViewController