Popover Doesn't Work on iPhone - ios

I implemented a Popover in my application and tested it. It will work fine on iPad but when I test it on iPhone, instead of showing Popover it will show the full storyboard. Please help me.
Here is my code:
#IBAction func MenuIsClick(sender: AnyObject) {
var moveToNextVC:MenuViewController
moveToNextVC = self.storyboard?.instantiateViewControllerWithIdentifier("MenuViewController") as! MenuViewController
moveToNextVC.modalPresentationStyle = .Popover
moveToNextVC.preferredContentSize = CGSizeMake(200, 200)
if let popoverController = moveToNextVC.popoverPresentationController {
popoverController.sourceView = sender as! UIView
popoverController.sourceRect = CGRect(x: 0, y: 0, width: 85, height: 30)
popoverController.permittedArrowDirections = .Any
popoverController.delegate = self
}
presentViewController(moveToNextVC, animated: true, completion: nil)
}
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController!, traitCollection: UITraitCollection!) -> UIModalPresentationStyle {
return .None
}
Edit: As Popover is not work on iPhone but when a refer this EthanStrider/iOS-Projects it will work fine. How?

UIPopoverController's are only available on iPad.
Popover controllers are for use exclusively on iPad devices.
Attempting to create one on other devices results in an exception.
Though with iOS 8+, it no longer crashes, it will be executed as full screen modal presentation..

A UIPopoverController is meant for use only on iPad devices. You can refer to the Apple docs to verify.
If you really want a popover on iPhone, you can use a third-party control like WYPopoverController.

you can use this control else.
https://github.com/50pixels/FPPopover/

For me the problem was the .none parameter in this delegate method. When I added UIModalPresentationStyle in front of it - it started to work!
// Override the iPhone behavior that presents a popover as fullscreen
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.none
}
The reason was that I had another .none case defined in an enum in my project with another underlying Int value (which is of course bad practice, so please avoid that to begin with).

Related

Popover presentation style on iPhone devices - possible any more?

I'm trying to define a popover view attached to a view like this:
Here's my code:
class MyController: UIViewController, UIPopoverPresentationControllerDelegate {
...
func displaySignOut(_ sender: UIButton) {
let vc = UIStoryboard(name: "Main", bundle: nil)
.instantiateViewController(withIdentifier: "signOutPopover")
vc.modalPresentationStyle = .popover
vc.preferredContentSize = CGSize(width: 100, height: 30)
present(vc, animated: true, completion: nil)
let pc = vc.popoverPresentationController!
pc.sourceView = sender
pc.sourceRect = sender.bounds
pc.delegate = self
}
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
return .none
}
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
}
Because the popover is so small, I'd like to use this style on all devices. I've followed the usual advice (e.g., here) on overriding adaptivePresentationStyle to return UIModalPresentationStyle.none.
This works fine on iPad devices, but on iPhones, it doesn't. On smaller iPhone devices, it comes up full screen all the time. On larger screens (e.g., iPhone 7 Plus), it comes up wrong, but, weirdly, switches to a popover presentation (in both portrait and landscape) if I rotate the device after the popover appears. (If I dismiss the popover and bring it up again, it's wrong again until I rotate the device.) Furthermore, in landscape it comes up in a strange configuration (not full screen as in portrait):
Unlike with a popover presentation, this does not dismiss if I tap outside the popover view itself.
The Apple documentation says (in part):
In a horizontally compact environment, popovers adapt to the UIModalPresentationOverFullScreen presentation style by default.
The "by default" strongly suggests that there's a way to override this behavior. But (as is consistent with this post), overriding adaptivePresentationStyle in the delegate doesn't seem to be the way to do this any more (although it used to work). So is there a new way to modify the default behavior?
I'm using XCode 8.3.3 and Swift 3.1, targeting iOS 9+.
I have created one custom class with storyboard inside that connect
outlet of button and implemented below code.
import UIKit
class PopOverViewController: UIViewController {
#IBOutlet weak var button: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
button.backgroundColor = UIColor.purple
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//Updating the popover size
override var preferredContentSize: CGSize {
get {
let size = CGSize(width: 80, height: 60)
return size
}
set {
super.preferredContentSize = newValue
}
}
//Setup the ViewController for popover presentation
func updatePopOverViewController(_ button: UIButton?, with delegate: AnyObject?) {
guard let button = button else { return }
modalPresentationStyle = .popover
popoverPresentationController?.permittedArrowDirections = [.any]
popoverPresentationController?.backgroundColor = UIColor.purple
popoverPresentationController?.sourceView = button
popoverPresentationController?.sourceRect = button.bounds
popoverPresentationController?.delegate = delegate
}
}
And then Inside ViewController implemented one function to show
popOver on iphone
func showPopOver(button: UIButton!) {
let viewController = PopOverViewController()
viewController.updatePopOverViewController(button, with: self)
present(viewController, animated: true, completion: nil)
}
Note:- Tested and this should work on Portrait as well Landscape mode
iOS 15 has some new ways to solve this problem.
Take a look at the WWDC21 Session "Customize and Resize Sheets in UIKit" https://developer.apple.com/wwdc21/10063
Pretty simple new interface for popovers and customized sheets. Shows how to do non-modal interaction with pop over and the view behind it.

Segue to popover for iPhone not working in iOS 10?

I wanted to segue to a popover in iOS 10, this piece of code used to work fine on iPhone but not now (it shows full screen), what have I done wrong? The segue is set to "Present As Popover".
override func prepare(for segue:UIStoryboardSegue, sender:AnyObject!) {
if segue.identifier == "about" {
let aboutController = segue.destination as! AboutController
aboutController.preferredContentSize = CGSize(width:300, height:440)
let popoverController = aboutController.popoverPresentationController
if popoverController != nil {
popoverController!.delegate = self
popoverController!.backgroundColor = UIColor.black
}
}
}
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return .none
}
Many function have been renamed in Swift 3, including adaptivePresentationStyleForPresentationController - this is now adaptivePresentationStyle(for:)
Change your code to
func adaptivePresentationStyle(for controller:UIPresentationController) -> UIModalPresentationStyle {
return .none
}
Since your function name didn't match it wasn't being called and because it is an optional function in the protocol, you didn't get a warning.
Popover is an iPad only feature.
UIKit is smart enough to figure out it should present it modally on iPhone/iPod.

How to code customized pickers in a class of UIView?

I’d like to code a view (popup – window) including two picker on it in order to enter weeks (of Year) and years with two separate picker views. Firstly, I started by creating a new class as subclass of UIView. Next up, I coded the windows, which should pop up, in case it is called.
Now I’ve the problem, that I can’t fill my two picker views with data, as UIView does not support UIPickerViewDataSource.
How can I solve that problem, as I only want to show it as a small pop up and not open an entire UIViewController.
It's supposed to be a controller, displayed in a popover.
The presenter should be UIPopoverPresentationControllerDelegate with overridden method to support popovers on iPhone (by default, they are gonna be presented modally).
extension ItemViewController: UIPopoverPresentationControllerDelegate {
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return .None
}
}
Use this method to present your picker controller:
func instantiatePicker(picker: UIViewController, sender: UIView) {
picker.modalPresentationStyle = .Popover
let ppc = picker.popoverPresentationController!
ppc.delegate = self
ppc.permittedArrowDirections = .Any
ppc.sourceView = sender
ppc.sourceRect = sender.bounds
presentViewController(picker, animated: true, completion: nil)
}
In your picker controller override this property to adjust popover size to your desire, like that:
override var preferredContentSize: CGSize {
get {
return CGSize(width: datePicker.bounds.width, height: datePicker.bounds.height + anotherPicker.bounds.height)
}
set {
super.preferredContentSize = newValue
}
}

Swift - UIPopoverController in iOS 8

I'm trying to add a simple popoverController to my iphone app, and I'm currently struggling with the classic "blank screen" which covers everything when I tap the button.
My code looks like this:
#IBAction func sendTapped(sender: UIBarButtonItem) {
var popView = PopViewController(nibName: "PopView", bundle: nil)
var popController = UIPopoverController(contentViewController: popView)
popController.popoverContentSize = CGSize(width: 3, height: 3)
popController.presentPopoverFromBarButtonItem(sendTappedOutl, permittedArrowDirections: UIPopoverArrowDirection.Up, animated: true)
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController!) -> UIModalPresentationStyle {
// Return no adaptive presentation style, use default presentation behaviour
return .None
}
}
The adaptivePresentationStyleForPresentationController-function was just something I added because I read somewhere that this is what you need to implement to get this function on the iphone. But still: there is still a blank image covering the whole screen, and I do not know how to fix it.
Any suggestions would be appreciated.
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.

UIPopoverPresentationController displaying popover as full screen

I am trying to use UIPopoverPresentationController to display a popover that doesn't take up the whole screen. I've followed many different tutorials with no luck.
Here is my code. It correctly instantiates the ViewController, but it takes up the entire screen instead of just a smaller screen as I defined in preferredContentSize.
func showPopover() {
let vc = self.storyboard?.instantiateViewControllerWithIdentifier("PopupTimePickerViewController") as PopupTimePickerViewController
vc.modalPresentationStyle = .Popover
vc.preferredContentSize = CGSizeMake(200, 100)
if let presentationController = vc.popoverPresentationController {
presentationController.delegate = self
presentationController.permittedArrowDirections = .Up
presentationController.sourceView = self.view
presentationController.sourceRect = CGRectMake(0, 0, 50, 50)
self.presentViewController(vc, animated: true, completion: nil)
}
}
Update 9/27/16 with correct answer
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
return .none
}
In iPhone, you should add the following in order to present a popover.
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController!) -> UIModalPresentationStyle {
// Return no adaptive presentation style, use default presentation behaviour
return .None
}
For Swift3/IOS10, looks like we need to do some thing like
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle
{
return .none
}
Adding this answer, in case, someone runs into this problem as i did when migrating to swift3/IOS10
For Swift3+/IOS10+, when dealing with iPhone:
You must add UIPopoverPresentationControllerDelegate the delegate at:
class YourClass: UIViewController, UIPopoverPresentationControllerDelegate { ...
Then implement in this same parent class (which will show the popover) the method below.
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle
{
return .none
}
And then set the popover configuration below:
myPopover.modalPresentationStyle = .popover
myPopover.popoverPresentationController?.sourceRect = VIEWTOPOINTTHEARROW.frame
myPopover.popoverPresentationController?.sourceView = self.view
myPopover.popoverPresentationController?.delegate = self
Also you may set some configuration for the popover class
class MyPopover: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//popover size
self.preferredContentSize = CGSize(width: 320, height: 200)
//sets the arrow of the popover to same color of background
self.popoverPresentationController?.backgroundColor = self.view.backgroundColor
}
}
The accepted answer is correct. For completeness, see Adapting Presented View Controllers to a New Style in the Apple docs:
Use the delegate’s adaptivePresentationStyleForPresentationController: method to specify a different presentation style than the default. When transitioning to a compact environment, the only supported styles are the two full-screen styles or UIModalPresentationNone. Returning UIModalPresentationNone tells the presentation controller to ignore the compact environment and continue using the previous presentation style. In the case of a popover, ignoring the change gives you the same iPad-like popover behavior on all devices.
Make sure that the required configurations from Presenting a View Controller in a Popover are met:
After setting the modal presentation style [of the presented view controller] to UIModalPresentationPopover, configure the following popover-related attributes:
Set the preferredContentSize property of your view controller to the desired size.
Set the popover anchor point using the associated UIPopoverPresentationController object, which is accessible from the
view controller’s popoverPresentationController property.
Set only one of the following:
Set the barButtonItem property to a bar button item.
Set the sourceView and sourceRect properties to a specific region in one of your views.
iOS 12 / Swift 4
There's also the possibility to show the popover on IPhone's as fullscreen and on IPad's as a popover.
Just return .popover for adaptivePresentationStyle():
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return .popover
}
and set the popover-configuration like #mourodrigo did:
dialog.modalPresentationStyle = .popover
dialog.popoverPresentationController?.delegate = self
dialog.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection(rawValue: 0)
dialog.popoverPresentationController?.sourceView = view
dialog.popoverPresentationController?.sourceRect = view.frame
objective-c version:
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller {
return UIModalPresentationNone;
}

Resources