How to present popover properly in iOS 8

折月煮酒 提交于 2019-11-26 15:37:08
Joris416

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]; } 
user2941395

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 ADD
UIPopoverPresentationControllerDelegate, 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.

ingconti

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!