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
}
Related
I am trying to lay out a popover view when a button on current view is pressed. This works fine with following code but problem is that the popover view does not take the size from .preferredContentSize.
IngredientVC.preferredContentSize = CGSize(width: 200, height: 300)
Popover view has height and width of current view. How do I make Popover view smaller size please?
#IBAction func actionIngredients(_ sender: Any)
{
// Load and configure your view controller.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let IngredientVC = storyboard.instantiateViewController(
withIdentifier: "testViewIdentifier")
//let IngredientVC:testViewController = testViewController()
// Use the popover presentation style for your view controller.
IngredientVC.modalPresentationStyle = .popover
IngredientVC.preferredContentSize = CGSize(width: 200, height: 300)
// Specify the anchor point for the popover.
//IngredientVC.popoverPresentationController?.barButtonItem =
//optionsControl
//let popovercontroller = optionsVC.popoverPresentationController
IngredientVC.popoverPresentationController?.delegate = self
IngredientVC.popoverPresentationController?.sourceView = self.view
IngredientVC.popoverPresentationController?.sourceRect = CGRect(x:self.view.frame.width/2, y: self.view.frame.height/2,width: 200,height: 300)
IngredientVC.popoverPresentationController?.permittedArrowDirections = [.down, .up]
// Present the view controller (in a popover).
self.present(IngredientVC, animated: true)
}
Note: I have popover view controller in Storyboard with Simulated Metrics size as "Freeform".
I figured out that all I needed was following function -
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle
{
return UIModalPresentationStyle.none
}
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 :)
I am presenting a modal popover view like this:
let popover = StatueSelectionController(collectionViewLayout: UICollectionViewFlowLayout())
popover.delegate = self
popover.modalPresentationStyle = .popover
popover.popoverPresentationController?.barButtonItem = navigationItem.rightBarButtonItem
popover.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection.up;
popover.preferredContentSize = CGSize(width: 200, height: 300)
present(popover, animated: true, completion: nil)
The popover.delegate = self has nothing to do with UIPopoverControllerDelegate although it does implement that protocol.
The problem is that the popover takes up the whole view. StatueSelectionController, which is a UICollectionViewController, fills up the whole screen and does not change for preferredContentSize.
What am I doing wrong here?
If you want to force the popOver to not cover the full screen on an iPhone, you would have to add a UIPopoverPresentationControllerDelegate method in your code
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
return .none
}
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)
}
}
I want to use safari cookies to authenticate users for my app. I am able to do it with SFSafariViewController. But the problem is i have UIWebView in my app to show some information. Even though user is logged in using safari, they are asked to login again through UIWebView. I want to sync this. Means if user is logged in by safari he should not have to login again in app.I know that safari and uiwebview don't share cookies and so i want to move everything to safari. Would it be possible to show safari inside of a view controller?
Thanks,
Richa
PopoverViewController method
let vc = SFSafariViewController(url: URL, entersReaderIfAvailable:false)
vc.modalPresentationStyle = .popover
vc.preferredContentSize = CGSize(width: self.view.frame.width/2, height: self.view.frame.height/2) // Or put any size
if let popover = vc.popoverPresentationController {
popover.sourceView = self.view // You can also put the source button
popover.permittedArrowDirections = .any
popover.sourceRect = CGRect(x: 0, y: 0, width: 85, height: 30)
popover.delegate = self
self.present(vc, animated: true, completion: nil)
}
Then declare this subclass:
class ViewController: UIViewController, UIPopoverPresentationControllerDelegate
But this is only work for iPad, so put this:
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
Result