Dismiss popover viewController when tapped elsewhere - ios

I'm presenting a popover viewController on top of a UITableView. How can i dismiss this popover when tapped outside of it? I'm trying to call it from the didSelectRow method, but the tap isn't detected. Any suggestion?
Thanks!
this is my code:
let addFriendsPopoverViewController = storyboard?.instantiateViewController(withIdentifier: "HomePopOver") as! HomePopOverViewController
addFriendsPopoverViewController.index = (sender.tag)!
addFriendsPopoverViewController.delegate = self
addFriendsPopoverViewController.isModalInPopover = true
addFriendsPopoverViewController.modalPresentationStyle = UIModalPresentationStyle.popover
addFriendsPopoverViewController.preferredContentSize = CGSize(width: 210, height: 40)
let popoverMenuViewController = addFriendsPopoverViewController.popoverPresentationController
popoverMenuViewController!.permittedArrowDirections = .down
popoverMenuViewController!.delegate = self
popoverMenuViewController!.sourceView = self.view
popoverMenuViewController!.sourceRect = CGRect(
x: UIScreen.main.bounds.width - 105,
y: 50,
width: 1,
height: 1)
present(
addFriendsPopoverViewController,
animated: true,
completion: nil)

A view controller presented in a UIPopoverController, or presented using UIModalPresentationPopover, will automatically be dismissed when the user taps outside the popover, unless you have set isModalInPopover or implemented the delegate method which prevents it.
If you need some code to run when this happens, then you'll need to implement a delegate method too.
Which specific methods depend on whether you're using a UIPopoverController or UIModalPresentationPopover. The tags on your question suggest the former, but that's quite an old-fashioned (and deprecated) way of doing it.

Even though you have found your answer, I wanted to share my solution because I had the same problem and after I spent some time to figure it out, I have found what the problem was. It was not actually because of something missing but because of something is implemented in vain.
Although I don't know why it happens but if following method implemented in your code, that may cause popover not to dismiss by tapping anywhere else than UIBarButtonItem itself.
func prepareForPopoverPresentation(_ popoverPresentationController: UIPopoverPresentationController) {
popoverPresentationController.permittedArrowDirections = .any
popoverPresentationController.barButtonItem = UIBarButtonItem(customView: categoryButton)
}
Here's the rest of implementation I have made for popover:
extension SearchViewController:UIPopoverPresentationControllerDelegate {
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
func presentPopover(sender: UIButton) {
let popoverContentController = PopoverCategoryViewController()
let nav = UINavigationController(rootViewController: popoverContentController)
nav.modalPresentationStyle = UIModalPresentationStyle.popover
nav.isNavigationBarHidden = true
let popover = nav.popoverPresentationController
popover?.backgroundColor = ChaptifyColor.backgroundGray
popover?.delegate = self
popover?.sourceView = sender
popover?.sourceRect = CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: sender.bounds.width, height: sender.bounds.height))
popoverContentController.preferredContentSize = CGSize(width: 300, height: 300)
self.present(nav, animated: true, completion: nil)
}
}

Related

Get rid of shadow form popover view controller (Swift)

I am trying to create number pad in iPad using popover view controller. Everything is achieved but there is a shadow beneath the pop view. I tried to remove that shadow but nothing worked for me. Here is my code which presents pop over view in my view controller.
let vc = self.storyboard?.instantiateViewController(withIdentifier: "PopOverVC") as? PopOverVC
vc?.modalPresentationStyle = .popover
vc?.preferredContentSize = CGSize(width: 280, height: 425)
vc?.delegate = self
if let popoverPresentationController = vc?.popoverPresentationController {
popoverPresentationController.permittedArrowDirections = [.down, .up, .right, .left]
popoverPresentationController.sourceView = self.view
popoverPresentationController.sourceRect = txtNumber.frame
popoverPresentationController.delegate = self
if let popoverController = vc {
present(popoverController, animated: false, completion: nil)
}
}
Can anybody help me removing the shadow? Thanks in advance!!

Presenting one ViewController over another partially

I have a MapViewController that is basically a MKMapView and presents a map with custom annotations.
Right now I am trying to present another ViewController from the bottom containing additional filters that the user will be able to use on his journey.
However I ran into a problem, when I am presenting the new FilterMenuViewController as a child of MapViewController the MapViewController disappears.
This is what it looks like:
Initial state
Button to present new controller tapped
New controller presented but the MapViewController disappearing
The code that takes care of the interaction is as follows:
MapViewController variables declaration:
var filterMenuVC = FilterMenuViewController()
var isFilterMenuOpened = false
MapViewController viewDidLoad():
filterMenuVC = storyboard?.instantiateViewController(withIdentifier: "FilterMenuViewController") as! FilterMenuViewController
MapViewController showFilterMenu button action:
#IBAction func showFilterMenu(_ sender: UIButton) {
// Presents the filter menu
if isFilterMenuOpened == true {
isFilterMenuOpened = false
filterMenuVC.willMove(toParentViewController: nil)
filterMenuVC.view.removeFromSuperview()
filterMenuVC.removeFromParentViewController()
} else if isFilterMenuOpened == false {
isFilterMenuOpened = true
self.addChildViewController(filterMenuVC)
self.view.addSubview(filterMenuVC.view)
filterMenuVC.didMove(toParentViewController: self)
}
}
Try this, the view shows from top and reverse, here is the image: https://imgur.com/a/gzIGjEa
if isFilterMenuOpened{
if let searching = self.childViewControllers.first as? ViewController{
UIView.animate(withDuration: 0.7, animations: {
searching.view.frame = CGRect.init(x: 0,
y: self.view.frame.origin.y-308,
width: self.view.frame.size.width,
height: 308)
}, completion: {(boos) in
searching.removeFromParentViewController()
searching.dismiss(animated: true, completion: nil)
self.isFilterMenuOpened = false
})
}
}else{
let search = self.storyboard?.instantiateViewController(withIdentifier: "searchView") as! ViewController
search.view.frame = CGRect.init(x: 0, y: self.view.frame.origin.y-308, width: self.view.frame.size.width, height: 308) //The View controller height same size of your view in storyboard
search.delegateSearch = self
self.addChildViewController(search)
UIView.animate(withDuration: 0.5, animations: {
search.view.frame = CGRect.init(x: 0, y: self.view.frame.origin.y, width: self.view.frame.size.width, height: 308)
})
self.view.addSubview(search.view)
self.didMove(toParentViewController: search)
isFilterMenuOpened = true
}
The problem was that I created a segue "show" from the button to the ViewController which conflicted with adding the controller to the current view, it pushed into it instead and the MapViewController got deallocated.
So I just deleted the segue from sotryboard and added the child programatically, it works like charm now.
Was a stupid mistake, but maybe this will help someone who runs into the same problem :)

Display popover as full screen for iPhone

I am trying to use UIPopoverPresentationController to display a popover that doesn't take up the whole screen. already checked this and other tutorials, but don't worked.
Here my code:
#IBAction func temp(_ sender: UIButton) {
let vc = UIStoryboard(name: "StayView", bundle: nil).instantiateViewController(withIdentifier: "StayViewPopOverViewController") as! StayViewPopOverViewController
vc.modalPresentationStyle = .popover
vc.preferredContentSize = CGSize(width: 180, height: 75)
let popover = vc.popoverPresentationController!
popover.sourceView = self.btnTemp
popover.sourceRect = self.btnTemp.bounds
popover.delegate = self
self.present(vc, animated: true, completion: nil)
}
My delegate method:
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController!) -> UIModalPresentationStyle {
return .none
}
but that cover Whole screen.
I tried to put breakpoint on delegate method but interpreter didn't stop on that.
can anyBody have any solution or any suggetions?
Upated: I want to achieve like this:
Finally I Got the answer.
Just need to update my delegate method like this:
func adaptivePresentationStyle(
for controller: UIPresentationController,
traitCollection: UITraitCollection)
-> UIModalPresentationStyle {
return .none
}
Thats It... Works Great!!!
Update following lines
vc.modalPresentationStyle = .popover
vc.preferredContentSize = CGSize(width: 180, height: 75)
with
vc.modalPresentationStyle = .overFullScreen
vc.preferredContentSize = view.frame.size

Modify width of Popover View Controller

I am trying modify the width of my popover, which is a UITableViewController, so that it only takes up half of the width of the parent view. The popover is called programmatically when a button in another UITableView (the parent view) is tapped. I tried setting the preferredContentSize of the popover and setting the sourceRect but the popover still takes over the entire screen.
class MyTableViewController: UITableViewController, UICollectionViewDataSource, UICollectionViewDelegate, UIDynamicAnimatorDelegate, UIGestureRecognizerDelegate, CLLocationManagerDelegate, UIPopoverPresentationControllerDelegate, UIAdaptivePresentationControllerDelegate {
...
func goToPlaces(button: UIButton) {
let fromRect = CGRectMake(50.0, 50.0, self.view.bounds.width / 2.0, self.view.bounds.height)
let popoverVC = storyboard?.instantiateViewControllerWithIdentifier("otherPlaces")
popoverVC?.modalPresentationStyle = .OverFullScreen
presentViewController(popoverVC!, animated: true, completion: nil)
popoverVC?.view.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.6)
popoverVC?.preferredContentSize = CGSizeMake(self.view.bounds.width / 2.0, self.view.bounds.height)
let popoverController = popoverVC?.popoverPresentationController
popoverPresentationController?.sourceView = self.view
popoverPresentationController?.sourceRect = fromRect
popoverController?.permittedArrowDirections = .Any
popoverController?.delegate = self
}
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return .None
}
EDIT:
When I do a print of
popoverPresentationController?.sourceView and
popoverPresentationController?.sourceRect
they both return nil for some reason
You are asking for
popoverVC?.modalPresentationStyle = .OverFullScreen
so you get it covering the whole screen. Try using:
popoverVC?.modalPresentationStyle = .Popover
The
presentViewController(popoverVC!, animated: true, completion: nil)
should also be last so that the delegate can get the calls for which it wants to respond. (I think -- it might not matter if UIKit is actually delaying the presentation.)
Try using popoverVC.modalPresentationStyle = UIModalPresentationStyle.PageSheet,

Present UISearchBar results as UIPopoverPresentationController iOS 9

I have a ParentViewController with a UISearchBar, and a ChildTableViewController with a tableView where the results from the search will be displayed. When I tap on the searchBar, a popover should present with all the results that conform to the filter written on the searchBar. This means, at the beginning, all results should be displayed in a popoverController.
The problem is that the results are shown occupying the whole screen, instead of being presented in a popover. Below is the code corresponding to ParentViewController where the popover should be presented.
func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
let childController = ChildTableViewController()
childController.modalPresentationStyle = .Popover
childController.preferredContentSize = CGSize(width: 50, height: 100)
let popover = childController.popoverPresentationController
popover?.permittedArrowDirections = .Any
popover?.delegate = self
popover?.sourceView = self.view
popover?.sourceRect = CGRect(x: 200, y: 200, width: 1, height: 1)
presentViewController(childController, animated: true,completion: nil)
}
I am using Xcode 7 and iOS 9.
What you need to do is to implement the following method which is part of the UIPopoverPresentationControllerDelegate protocol:
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller {
return UIModalPresentationNone; // This will force a popover display
}

Resources