I'm trying to add a UIPopoverView to my Swift iOS 8 app, but I am unable to access the PopoverContentSize property, as the popover does not show in the correct shape. my code:
var popover: UIPopoverController? = nil func addCategory() { var newCategory = storyboard.instantiateViewControllerWithIdentifier("NewCategory") as UIViewController var nav = UINavigationController(rootViewController: newCategory) popover = UIPopoverController(contentViewController: nav) popover!.setPopoverContentSize(CGSizeMake(550, 600), animated: true) popover!.delegate = self popover!.presentPopoverFromBarButtonItem(self.navigationItem.rightBarButtonItem, permittedArrowDirections: UIPopoverArrowDirection.Any, animated: true) }
output:
When I am doing the same thing through UIPopoverPresentationController, I still don't get it done. this is my code:
func addCategory() { var popoverContent = self.storyboard.instantiateViewControllerWithIdentifier("NewCategory") as UIViewController var nav = UINavigationController(rootViewController: popoverContent) nav.modalPresentationStyle = UIModalPresentationStyle.Popover var popover = nav.popoverPresentationController as UIPopoverPresentationController popover.delegate = self popover.popoverContentSize = CGSizeMake(1000, 300) popover.sourceView = self.view popover.sourceRect = CGRectMake(100,100,0,0) self.presentViewController(nav, animated: true, completion: nil) }
I get the exact same output.
How do I customize the size of my popover? Any help would be highly appreciated!
Okay, A housemate took a look at it and figured it out:
func addCategory() { var popoverContent = self.storyboard?.instantiateViewControllerWithIdentifier("NewCategory") as UIViewController var nav = UINavigationController(rootViewController: popoverContent) nav.modalPresentationStyle = UIModalPresentationStyle.Popover var popover = nav.popoverPresentationController popoverContent.preferredContentSize = CGSizeMake(500,600) popover.delegate = self popover.sourceView = self.view popover.sourceRect = CGRectMake(100,100,0,0) self.presentViewController(nav, animated: true, completion: nil) }
That's the way.
You don't talk to the popover itself anymore, you talk to the view controller inside of it to set the content size, by calling the property preferredContentSize
Actually it is much simpler than that. In the storyboard you should make the viewcontroller you want to use as popover and make a viewcontroller class for it as usual. Make a segue as shown below from the object you want to open the popover, in this case the UIBarButton
named "Config".
In the "mother viewcontroller" implement the UIPopoverPresentationControllerDelegate
and the delegate method:
func popoverPresentationControllerDidDismissPopover(popoverPresentationController: UIPopoverPresentationController) { //do som stuff from the popover }
Override the prepareForSeque
method like this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { //segue for the popover configuration window if segue.identifier == "yourSegueIdentifierForPopOver" { if let controller = segue.destinationViewController as? UIViewController { controller.popoverPresentationController!.delegate = self controller.preferredContentSize = CGSize(width: 320, height: 186) } } }
And you're done. And you can now treat the popover view as any other view, ie. add fields and what not! And you get hold of the the content controller by using the popoverPresentationController.presentedViewController
method in the UIPopoverPresentationController
.
Also on an iPhone you would have to overwrite
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle { return UIModalPresentationStyle.none }
I found a complete example of how to get this all to work so that you can always display a popover no matter the device/orientation https://github.com/frogcjn/AdaptivePopover_iOS8_Swift.
The key is to implement UIAdaptivePresentationControllerDelegate
func adaptivePresentationStyleForPresentationController(PC: UIPresentationController!) -> UIModalPresentationStyle { // This *forces* a popover to be displayed on the iPhone return .None }
Then extend the example above (from Imagine Digital):
nav.popoverPresentationController!.delegate = implOfUIAPCDelegate
Swift 2.0
Well I worked out. Have a look. Made a ViewController in StoryBoard. Associated with PopOverViewController class.
import UIKit class PopOverViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() self.preferredContentSize = CGSizeMake(200, 200) self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .Done, target: self, action: "dismiss:") } func dismiss(sender: AnyObject) { self.dismissViewControllerAnimated(true, completion: nil) } }
See ViewController:
// ViewController.swift import UIKit class ViewController: UIViewController, UIPopoverPresentationControllerDelegate { func showPopover(base: UIView) { if let viewController = self.storyboard?.instantiateViewControllerWithIdentifier("popover") as? PopOverViewController { let navController = UINavigationController(rootViewController: viewController) navController.modalPresentationStyle = .Popover if let pctrl = navController.popoverPresentationController { pctrl.delegate = self pctrl.sourceView = base pctrl.sourceRect = base.bounds self.presentViewController(navController, animated: true, completion: nil) } } } override func viewDidLoad(){ super.viewDidLoad() } @IBAction func onShow(sender: UIButton) { self.showPopover(sender) } func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle { return .None } }
Note: The func showPopover(base: UIView) method should be placed before ViewDidLoad. Hope it helps !
In iOS9 UIPopoverController is depreciated. So can use the below code for Objective-C version above iOS9.x,
- (IBAction)onclickPopover:(id)sender { UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:[NSBundle mainBundle]]; UIViewController *viewController = [sb instantiateViewControllerWithIdentifier:@"popover"]; viewController.modalPresentationStyle = UIModalPresentationPopover; viewController.popoverPresentationController.sourceView = self.popOverBtn; viewController.popoverPresentationController.sourceRect = self.popOverBtn.bounds; viewController.popoverPresentationController.permittedArrowDirections = UIPopoverArrowDirectionAny; [self presentViewController:viewController animated:YES completion:nil]; }
Here i Convert "Joris416" Swift Code to Objective-c,
-(void) popoverstart { ViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:@"PopoverView"]; UINavigationController *nav = [[UINavigationController alloc]initWithRootViewController:controller]; nav.modalPresentationStyle = UIModalPresentationPopover; UIPopoverPresentationController *popover = nav.popoverPresentationController; controller.preferredContentSize = CGSizeMake(300, 200); popover.delegate = self; popover.sourceView = self.view; popover.sourceRect = CGRectMake(100, 100, 0, 0); popover.permittedArrowDirections = UIPopoverArrowDirectionAny; [self presentViewController:nav animated:YES completion:nil]; } -(UIModalPresentationStyle) adaptivePresentationStyleForPresentationController: (UIPresentationController * ) controller { return UIModalPresentationNone; }
Remember to ADDUIPopoverPresentationControllerDelegate, UIAdaptivePresentationControllerDelegate
This is best explained on the iOS8 Day-by-Day blog
In short, once you've set your UIViewController's modalPresentationStyle to .Popover, you can get hold of a UIPopoverPresentationClass (a new iOS8 class) via the controller's popoverPresentationController property.
my two cents for xcode 9.1 / swift 4.
class ViewController: UIViewController, UIPopoverPresentationControllerDelegate { override func viewDidLoad(){ super.viewDidLoad() let when = DispatchTime.now() + 0.5 DispatchQueue.main.asyncAfter(deadline: when, execute: { () -> Void in // to test after 05.secs... :) self.showPopover(base: self.view) }) } func showPopover(base: UIView) { if let viewController = self.storyboard?.instantiateViewController(withIdentifier: "popover") as? PopOverViewController { let navController = UINavigationController(rootViewController: viewController) navController.modalPresentationStyle = .popover if let pctrl = navController.popoverPresentationController { pctrl.delegate = self pctrl.sourceView = base pctrl.sourceRect = base.bounds self.present(navController, animated: true, completion: nil) } } } @IBAction func onShow(sender: UIButton){ self.showPopover(base: sender) } func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle{ return .none }
and experiment in:
func adaptivePresentationStyle...
return .popover
or: return .pageSheet.... and so on..
I made an Objective-C version of Imagine Digitals swift answer above. I don't think I missed anything as it seems to work under preliminary testing, if you spot something let me know, and I'll update it
-(void) presentPopover { YourViewController* popoverContent = [[YourViewController alloc] init]; //this will be a subclass of UIViewController UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:popoverContent]; nav.modalPresentationStyle = UIModalPresentationPopover; UIPopoverPresentationController* popover = nav.popoverPresentationController; popoverContent.preferredContentSize = CGSizeMake(500,600); popover.delegate = self; popover.sourceRect = CGRectMake(100,100,0,0); //I actually used popover.barButtonItem = self.myBarButton; [self presentViewController:nav animated:YES completion:nil]; }
Implement UIAdaptivePresentationControllerDelegate in your Viewcontroller. Then add :
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle{ return .none }
The following has a pretty comprehensive guide on how to configure and present popovers. https://www.appcoda.com/presentation-controllers-tutorial/
In summary, a viable implementation (with some updates from the original article syntax for Swift 4.2), to then be called from elsewhere, would be something like the following:
func showPopover(ofViewController popoverViewController: UIViewController, originView: UIView) { popoverViewController.modalPresentationStyle = UIModalPresentationStyle.popover if let popoverController = popoverViewController.popoverPresentationController { popoverController.delegate = self popoverController.sourceView = originView popoverController.sourceRect = originView.bounds popoverController.permittedArrowDirections = UIPopoverArrowDirection.any } self.present(popoverViewController, animated: true) }
A lot of this was already covered in the answer from @mmc, but the article helps to explain some of those code elements used, and also show how it could be expanded.
It also provides a lot of additional detail about using delegation to handle the presentation style for iPhone vs. iPad, and to allow dismissal of the popover if it's ever shown full-screen. Again, updated for Swift 4.2:
func adaptivePresentationStyle(for: UIPresentationController) -> UIModalPresentationStyle { //return UIModalPresentationStyle.fullScreen return UIModalPresentationStyle.none } func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle { if traitCollection.horizontalSizeClass == .compact { return UIModalPresentationStyle.none //return UIModalPresentationStyle.fullScreen } //return UIModalPresentationStyle.fullScreen return UIModalPresentationStyle.none } func presentationController(_ controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? { switch style { case .fullScreen: let navigationController = UINavigationController(rootViewController: controller.presentedViewController) let doneButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.done, target: self, action: #selector(doneWithPopover)) navigationController.topViewController?.navigationItem.rightBarButtonItem = doneButton return navigationController default: return controller.presentedViewController } } // As of Swift 4, functions used in selectors must be declared as @objc @objc private func doneWithPopover() { self.dismiss(animated: true, completion: nil) }
Hope this helps.
For those who wants to study!
I created an Open Source project for those who want to study and use Popover view for anypurpose. You can find the project here. https://github.com/tryWabbit/KTListPopup
来源:https://stackoverflow.com/questions/24635744/how-to-present-popover-properly-in-ios-8