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
}
Related
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
I am trying to present a PopOver view controller, specifically to show a small filters screen next to a TextField. However it is showing as a full-screen view controller. filters_button is the one that should trigger the pop-over. Any ideas why this is showing full screen as if it were a normal ViewController?
func showFilters(){
let tableViewController = UITableViewController()
tableViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
tableViewController.preferredContentSize = CGSizeMake(20, 20)
presentViewController(tableViewController, animated: true, completion: nil)
let popoverPresentationController = tableViewController.popoverPresentationController
popoverPresentationController?.sourceView = filters_button
popoverPresentationController?.sourceRect = CGRectMake(0, 0, filters_button.frame.size.width, filters_button.frame.size.height)
}
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return .None
}
Note: At the top of my class I declare that it conforms the "UIPopoverPresentationControllerDelegate" protocol
Fixed:
Given that for the PopOver to work on iPhone devices, you need to set the delegate of popoverPresentationController before the viewController is presented, that way the method below gets called by the delegate. So add
popoverPresentationController?.delegate = self
below
popoverPresentationController?.sourceRect = filters_button.frame
and move
self.presentViewController(filtersVC, animated: true, completion: nil)
to the end of the function.
You should add the following
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
return .none
}
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,
I'm trying to programmatically present a view via an adaptive popover (e.g. in a popover on an iPad, full screen on an iPhone). In order to be able to dismiss the presented view controller on the iPhone, I've tried wrapping it in a navigation controller as in https://stackoverflow.com/a/29956631/5061277 or the nice example here: https://github.com/shinobicontrols/iOS8-day-by-day/tree/master/21-alerts-and-popovers/AppAlert, which looks like:
import UIKit
class ViewController: UIViewController, UIPopoverPresentationControllerDelegate {
#IBAction func handlePopoverPressed(sender: UIView) {
let popoverVC = storyboard?.instantiateViewControllerWithIdentifier("codePopover") as! UIViewController
popoverVC.modalPresentationStyle = .Popover
// Present it before configuring it
presentViewController(popoverVC, animated: true, completion: nil)
// Now the popoverPresentationController has been created
if let popoverController = popoverVC.popoverPresentationController {
popoverController.sourceView = sender
popoverController.sourceRect = sender.bounds
popoverController.permittedArrowDirections = .Any
popoverController.delegate = self
}
}
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
// This line _IS_ reached in the debugger
NSLog("Delagate asked for presentation style");
return .FullScreen
}
func presentationController(controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
// This line _IS_NOT_ reached in the debugger
NSLog("Delegate asked for view controller");
return UINavigationController(rootViewController: controller.presentedViewController)
}
}
While the adaptivePresentationStyleForPresentationController delegate method is called, the presentationController viewControllerForAdaptivePresentationStyle delegate method is not called. As a result there is no way to dismiss the presented controller on an iPhone.
I've tried XCode 6.4 and 7.0b2 on iOS 8.1 through 8.4, both in the simulator and on a device, and in no case is my delegate asked for viewControllerForAdaptivePresentationStyle. Why? Is there a build setting I should be looking at, or could having XCode 7 installed be changing something? This exact code is presented as working in the links above.
You need to present it after configuring it. Alternatively use a segue to make it much easier.
You need to add this method:
-(UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller traitCollection:(UITraitCollection *)traitCollection{
return UIModalPresentationOverFullScreen;
}
The trick is that you must set the
presentation controller’s delegate before calling present(_:animated:completion:);
otherwise, the adaptive presentation delegate methods won’t be called:
let vc = MyViewController()
vc.modalPresentationStyle = .popover
if let pop = vc.popoverPresentationController {
pop.delegate = self // *
}
self.present(vc, animated: true)
I wish to create a small popover about 50x50px from a UIButton. I have seen methods using adaptive segue's but I have my size classes turn of thus meaning I can not use this features!
How else can I create this popover? Can I create it with code inside my button IBACtion? Or is there still a way I can do this with storyboards?
You can do one of the following two options :
Create an action for the UIButton in your UIViewController and inside present the ViewController you want like a Popover and your UIViewController has to implement the protocol UIPopoverPresentationControllerDelegate, take a look in the following code :
#IBAction func showPopover(sender: AnyObject) {
var popoverContent = self.storyboard?.instantiateViewControllerWithIdentifier("StoryboardIdentifier") as! UIViewController
popoverContent.modalPresentationStyle = .Popover
var popover = popoverContent.popoverPresentationController
if let popover = popoverContent.popoverPresentationController {
let viewForSource = sender as! UIView
popover.sourceView = viewForSource
// the position of the popover where it's showed
popover.sourceRect = viewForSource.bounds
// the size you want to display
popoverContent.preferredContentSize = CGSizeMake(200,500)
popover.delegate = self
}
self.presentViewController(popoverContent, animated: true, completion: nil)
}
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return .None
}
According to the book of #matt Programming iOS 8:
A popover presentation controller, in iOS 8, is a presentation controller (UIPresentationController), and presentation controllers are adaptive. This means that, by default, in a horizontally compact environment (i.e. on an iPhone), the .Popover modal presentation style will be treated as .FullScreen. What appears as a popover on the iPad will appear as a fullscreen presented view on the iPhone, completely replacing the interface.
To avoid this behavior in the iPhone you need to implement the delegate method adaptivePresentationStyleForPresentationController inside your UIViewController to display the Popover correctly.
The other way in my opinion is more easy to do, and is using Interface Builder, just arrange from the UIButton to create a segue to the ViewController you want and in the segue select the Popover segue.
I hope this help you.
Swift 4 Here is fully working code. So here you will see popup window with size of 250x250:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// in case if you don't want to make it via IBAction
button.addTarget(self, action: #selector(tapped), for: .touchUpInside)
}
#objc
private func tapped() {
guard let popVC = storyboard?.instantiateViewController(withIdentifier: "popVC") else { return }
popVC.modalPresentationStyle = .popover
let popOverVC = popVC.popoverPresentationController
popOverVC?.delegate = self
popOverVC?.sourceView = self.button
popOverVC?.sourceRect = CGRect(x: self.button.bounds.midX, y: self.button.bounds.minY, width: 0, height: 0)
popVC.preferredContentSize = CGSize(width: 250, height: 250)
self.present(popVC, animated: true)
}
}
// This is we need to make it looks as a popup window on iPhone
extension ViewController: UIPopoverPresentationControllerDelegate {
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
}
Take into attention that you have to provide popVC identifier to one viewController you want to present as a popup.
Hope that helps!
Here you can present a popover on button click.
func addCategory( _ sender : UIButton) {
var popoverContent = self.storyboard?.instantiateViewControllerWithIdentifier("NewCategory") as UIViewController
var nav = UINavigationController(rootViewController: popoverContent)
nav.modalPresentationStyle = UIModalPresentationStyle.Popover
var popover = nav.popoverPresentationController
popoverContent.preferredContentSize = CGSizeMake(50,50)
popover.delegate = self
popover.sourceView = sender
popover.sourceRect = sender.bounds
self.presentViewController(nav, animated: true, completion: nil)
}
Swift 4 Version
Doing most work from the storyboard
I added a ViewController, went to it's attribute inspector and ticked the "Use Preferred Explicit size". After that I changed the Width and Height values to 50 each.
Once this was done I ctrl clicked and dragged from the Button to the ViewController I added choosing "Present as Popover" and naming the segue Identifier as "pop"
Went to the ViewController where I had my Button and added the following code:
class FirstViewController: UIViewController, UIPopoverPresentationControllerDelegate {
#IBOutlet weak var popoverButton: UIButton! // the button
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "pop" {
let popoverViewController = segue.destination
popoverViewController.modalPresentationStyle = .popover
popoverViewController.presentationController?.delegate = self
popoverViewController.popoverPresentationController?.sourceView = popoverButton
popoverViewController.popoverPresentationController?.sourceRect = CGRect(x: 0, y: 0, width: popoverButton.frame.size.width, height: popoverButton.frame.size.height)
}
}
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.none
}
override func viewDidLoad() {
super.viewDidLoad()
}
}