Swift - Uipopovercontroller in iOS 8

Swift - UIPopoverController in iOS 8

The solution I implemented for this is based on an example presented in the 2014 WWDC session View Controller Advancements in iOS 8 (see the slide notes). Note that you do have to implement the adaptivePresentationStyleForPresentationController function as a part of the UIPopoverPresentationControllerDelegate, but that function should be outside of your sendTapped function in your main view controller, and you must specify UIPopoverPresentationControllerDelegate in your class declaration line in that file to make sure that your code modifies that behaviour. I also took the liberty to separate out the logic to present a view controller in a popover into its own function and added a check to make sure the function does not present the request view controller if it is already presented in the current context.

So, your solution could look something like this:

// ViewController must implement UIPopoverPresentationControllerDelegate
class TheViewController: UIViewController, UIPopoverPresentationControllerDelegate {
// ...
// The contents of TheViewController class
// ...

@IBAction func sendTapped(sender: UIBarButtonItem) {
let popView = PopViewController(nibName: "PopView", bundle: nil)
self.presentViewControllerAsPopover(popView, barButtonItem: sender)
}

func presentViewControllerAsPopover(viewController: UIViewController, barButtonItem: UIBarButtonItem) {
if let presentedVC = self.presentedViewController {
if presentedVC.nibName == viewController.nibName {
// The view is already being presented
return
}
}
// Specify presentation style first (makes the popoverPresentationController property available)
viewController.modalPresentationStyle = .Popover
let viewPresentationController = viewController.popoverPresentationController?
if let presentationController = viewPresentationController {
presentationController.delegate = self
presentationController.barButtonItem = barButtonItem
presentationController.permittedArrowDirections = .Up
}
viewController.preferredContentSize = CGSize(width: 30, height: 30)

self.presentViewController(viewController, animated: true, completion: nil)
}

func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return .None
}
}

Real world implementation

I implemented this approach for input validation on a sign up form in an in-progress app that I host on Github. I implemented it as extensions to UIVIewController in UIViewController+Extensions.swift. You can see it in use in the validation functions in AuthViewController.swift. The presentAlertPopover method takes a string and uses it to set the value of a UILabel in a GenericAlertViewController that I have set up (makes it easy to have dynamic text popovers). But the actual popover magic all happens in the presentViewControllerAsPopover method, which takes two parameters: the UIViewController instance to be presented, and a UIView object to use as the anchor from which to present the popover. The arrow direction is hardcoded as UIPopoverArrowDirection.Up, but that wouldn’t be hard to change.

UIPopoverController, Xcode 6, IOS 8 using Swift

Here is a simple example for iOS 8. Popover are presented using adaptivity apis in iOS 8.

class PlayerInformationTableViewController: UITableViewController, UIPopoverPresentationControllerDelegate, NSFetchedResultsControllerDelegate{

...

@IBAction func addPopover(sender: UIBarButtonItem){
let playerInformationViewController = PlayerInformationViewController()
playerInformationViewController.modalPresentationStyle = .Popover
playerInformationViewController.preferredContentSize = CGSizeMake(300, 300)

let popoverPresentationViewController = playerInformationViewController.popoverPresentationController
popoverPresentationViewController?.permittedArrowDirections = .Any
popoverPresentationViewController?.delegate = self
popoverPresentationController?.barButtonItem = sender
presentViewController(playerInformationViewController, animated: true, completion: nil)
}

func adaptivePresentationStyleForPresentationController(controller: UIPresentationController!) -> UIModalPresentationStyle{
return .None
}

}

How to present popover properly in iOS 8

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

UIPopoverController (swift)

Use

let popOver = UIPopoverController(contentViewController:imagePicker)

iOS 8: Storyboard - Delegate for UIPopoverController

Had the same issue recently. In iOS 8, you can access the UIPopoverPresentationController and set the UIPopoverPresentationControllerDelegate (rather than the UIPopoverController and -Delegate) through the popoverPresentationController of the destinationViewController, using this code:

override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
if let controller = segue.destinationViewController as? UIViewController {
controller.popoverPresentationController.delegate = self
}
}

How to make UIPopoverController (Swift)?

* Updated Answer *

class ViewController: UIViewController, UIPopoverControllerDelegate, UIPopoverPresentationControllerDelegate {

@IBOutlet weak var RoutineLabel: UIButton!

@IBAction func RoutineButton(sender: AnyObject) {

switch SDiPhoneVersion.deviceVersion() {
case DeviceVersion.iPad1, DeviceVersion.iPad2, DeviceVersion.iPadMini, DeviceVersion.iPad3, DeviceVersion.iPad4, DeviceVersion.iPadAir, DeviceVersion.iPadMiniRetina:

var popoverViewController = self.storyboard?.instantiateViewControllerWithIdentifier("RoutinesTableViewController") as UITableViewController
popoverViewController.modalPresentationStyle = .Popover
popoverViewController.preferredContentSize = CGSizeMake(300, 300)

let popoverPresentationViewController = popoverViewController.popoverPresentationController

popoverPresentationViewController?.permittedArrowDirections = UIPopoverArrowDirection.Up
popoverPresentationViewController?.delegate = self
popoverPresentationViewController?.sourceView = self.RoutineLabel
popoverPresentationViewController?.sourceRect = CGRectMake(RoutineLabel.frame.width / 2, RoutineLabel.frame.height,0,0)

presentViewController(popoverViewController, animated: true, completion: nil)

default:

println("iPhones")

}

}
}

Notes:

  • my PopPoverViewController is a UITableViewController
  • I use SDiPhoneVersion.deviceVersion to check for device version
  • I use a button to trigger it
  • I make the start of my pop up depend on RoutineLabel.frame

UIPopoverPresentationController on iOS 8 iPhone

You can override the default adaptive behaviour (UIModalPresentationFullScreen in compact horizontal environment, i.e. iPhone) using the
adaptivePresentationStyleForPresentationController: method available through UIPopoverPresentationController.delegate.

UIPresentationController uses this method to ask the new presentation style to use, which in your case, simply returning UIModalPresentationNone will cause the UIPopoverPresentationController to render as a popover instead of fullscreen.

Here's an example of the popover using a segue setup in storyboard from a UIBarButtonItem to "present modally" a UIViewController

class SomeViewController: UIViewController, UIPopoverPresentationControllerDelegate {

// override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) { // swift < 3.0
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "PopoverSegue" {
if let controller = segue.destinationViewController as? UIViewController {
controller.popoverPresentationController.delegate = self
controller.preferredContentSize = CGSize(width: 320, height: 186)
}
}
}

// MARK: UIPopoverPresentationControllerDelegate

//func adaptivePresentationStyleForPresentationController(controller: UIPresentationController!) -> UIModalPresentationStyle { // swift < 3.0
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
// Return no adaptive presentation style, use default presentation behaviour
return .None
}
}

This trick was mentioned in WWDC 2014 session 214 "View Controller Advancement in iOS8" (36:30)

UIPopoverController for iphone not working?

Edit: As stated by Soberman, since iOS 8 it is possible to present popovers on iPhone using public APIs, so this answer is probably not relevant anymore.


As stated in Apple's documentation on UIPopoverController:

Popover controllers are for use exclusively on iPad devices.

So there is no way to use this class in iPhone application unfortunately. But there are a couple of custom third-party implementations of the functionality provided by UIPopoverController which add iPhone support and more. See https://github.com/50pixels/FPPopover for example.

Edit: There also is another highly customizable popover implementation for both iPhone/iPad worth checking out: https://github.com/nicolaschengdev/WYPopoverController.



Related Topics



Leave a reply



Submit