UIPopoverPresentationController on iOS 8 iPhone
Solution 1:
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)
Solution 2:
If anybody wants to present a popover with code only, you can use the following approach.
OBJECTIVE - C
Declare a property of UIPopoverPresentationController
:
@property(nonatomic,retain)UIPopoverPresentationController *dateTimePopover8;
Use the following method to present the popover from UIButton:
- (IBAction)btnSelectDatePressed:(id)sender
{
UINavigationController *destNav = [[UINavigationController alloc] initWithRootViewController:dateVC];/*Here dateVC is controller you want to show in popover*/
dateVC.preferredContentSize = CGSizeMake(280,200);
destNav.modalPresentationStyle = UIModalPresentationPopover;
_dateTimePopover8 = destNav.popoverPresentationController;
_dateTimePopover8.delegate = self;
_dateTimePopover8.sourceView = self.view;
_dateTimePopover8.sourceRect = sender.frame;
destNav.navigationBarHidden = YES;
[self presentViewController:destNav animated:YES completion:nil];
}
Use the following method to present the popover from UIBarButtonItem:
- (IBAction)btnSelectDatePressed:(id)sender
{
UINavigationController *destNav = [[UINavigationController alloc] initWithRootViewController:dateVC];/*Here dateVC is controller you want to show in popover*/
dateVC.preferredContentSize = CGSizeMake(280,200);
destNav.modalPresentationStyle = UIModalPresentationPopover;
_dateTimePopover8 = destNav.popoverPresentationController;
_dateTimePopover8.delegate = self;
_dateTimePopover8.sourceView = self.view;
CGRect frame = [[sender valueForKey:@"view"] frame];
frame.origin.y = frame.origin.y+20;
_dateTimePopover8.sourceRect = frame;
destNav.navigationBarHidden = YES;
[self presentViewController:destNav animated:YES completion:nil];
}
Implement this delegate method too in your view controller:
- (UIModalPresentationStyle) adaptivePresentationStyleForPresentationController: (UIPresentationController * ) controller {
return UIModalPresentationNone;
}
To dismiss this popover, simply dismiss the view controller. Below is the code to dismiss the view controller:
-(void)hideIOS8PopOver
{
[self dismissViewControllerAnimated:YES completion:nil];
}
SWIFT
Use the following method to present the popover from UIButon:
func filterBooks(sender: UIButon)
{
let filterVC = FilterDistanceViewController(nibName: "FilterDistanceViewController", bundle: nil)
var filterDistanceViewController = UINavigationController(rootViewController: filterVC)
filterDistanceViewController.preferredContentSize = CGSizeMake(300, 205)
let popoverPresentationViewController = filterDistanceViewController.popoverPresentationController
popoverPresentationViewController?.permittedArrowDirections = .Any
popoverPresentationViewController?.delegate = self
popoverPresentationController?.barButtonItem = self.navigationItem.rightBarButtonItem
popoverPresentationViewController!.sourceView = self.view;
popoverPresentationViewController!.sourceRect = sender.frame
filterDistanceViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
filterDistanceViewController.navigationBarHidden = true
self.presentViewController(filterDistanceViewController, animated: true, completion: nil)
}
Use the following method to present the popover from UIBarButtonItem:
func filterBooks(sender: UIBarButtonItem)
{
let filterVC = FilterDistanceViewController(nibName: "FilterDistanceViewController", bundle: nil)
var filterDistanceViewController = UINavigationController(rootViewController: filterVC)
filterDistanceViewController.preferredContentSize = CGSizeMake(300, 205)
let popoverPresentationViewController = filterDistanceViewController.popoverPresentationController
popoverPresentationViewController?.permittedArrowDirections = .Any
popoverPresentationViewController?.delegate = self
popoverPresentationController?.barButtonItem = self.navigationItem.rightBarButtonItem
popoverPresentationViewController!.sourceView = self.view;
var frame:CGRect = sender.valueForKey("view")!.frame
frame.origin.y = frame.origin.y+20
popoverPresentationViewController!.sourceRect = frame
filterDistanceViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
filterDistanceViewController.navigationBarHidden = true
self.presentViewController(filterDistanceViewController, animated: true, completion: nil)
}
Implement this delegate method too in your view controller:
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle{
return .None
}
Please make sure to add delegate UIPopoverPresentationControllerDelegate
in .h/.m/.swift file
Solution 3:
PROBLEM: iPhone popover displays fullscreen and does not respect preferredContentSize value.
SOLUTION: Contrary to what Apple suggests in the UIPopoverPresentationController Class reference, presenting the view controller after getting a reference to the popover presentation controller and configuring it.
// Get the popover presentation controller and configure it.
//...
// Present the view controller using the popover style.
[self presentViewController:myPopoverViewController animated: YES completion: nil];
Solution 4:
Make sure to implement UIAdaptivePresentationControllerDelegate
like this:
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller {
return UIModalPresentationNone;
}
If you don't want full-screen popovers
Solution 5:
I've found some workaround.
On Xcode6.1, use presentationController.delegate
instead of popoverPresentationController.delegate
.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier compare:@"showPopOver"] == NSOrderedSame) {
UINavigationController * nvc = segue.destinationViewController;
UIPresentationController * pc = nvc.presentationController;
pc.delegate = self;
}
}
#pragma mark == UIPopoverPresentationControllerDelegate ==
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller
{
return UIModalPresentationNone;
}
In WWDC 2014 "View Controller Advancements in iOS8", below codes can show popover on iPhone.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UINavigationController * nvc = segue.destinationViewController;
UIPopoverPresentationController * pvc = nvc.popoverPresentationController;
pvc.delegate = self;
}
#pragma mark == UIPopoverPresentationControllerDelegate ==
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller
{
return UIModalPresentationNone;
}
But On Xcode 6.1, these codes shows FullScreen presentation... (nvc.popoverPresentationController is nil)
I doubt it might be an Apple's bug.