35

I want to always present a ViewController in a popover on all devices and all orientations. I tried to accomplish this by adopting the UIPopoverPresentationControllerDelegate and setting the sourceView and sourceRect.

This works very well for all devices and orientations, except the iPhone 6 Plus in landscape. In that case the view controller slides up from the bottom of the screen in a form sheet. How can I prevent that so that it will always appear in a popover?

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let popoverPresentationController = segue.destinationViewController.popoverPresentationController
popoverPresentationController?.delegate = self
popoverPresentationController?.sourceView = self.titleLabel!.superview
popoverPresentationController?.sourceRect = self.titleLabel!.frame }

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

All device are under iOS 8.2 or higher

Loegic
  • 3,390
  • 20
  • 33

4 Answers4

82

Implement the new adaptivePresentationStyleForPresentationController:traitCollection: method of UIAdaptivePresentationControllerDelegate:

- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller traitCollection:(UITraitCollection *)traitCollection {
    // This method is called in iOS 8.3 or later regardless of trait collection, in which case use the original presentation style (UIModalPresentationNone signals no adaptation)
    return UIModalPresentationNone;
}

UIModalPresentationNone tells the presentation controller to use the original presentation style which in your case will display a popover.

Joshua
  • 15,200
  • 21
  • 100
  • 172
  • 1
    Good call! I forgot that the delegate method changed for 8.3. –  May 27 '15 at 12:00
  • 1
    @PetahChristian Thanks! Yeah was quite a quiet change and doesn't appear to be documented other than in the API diffs. – Joshua May 27 '15 at 12:02
  • @Joshua YES ! I did implement - (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller { return UIModalPresentationNone; } but the new API solve my issue, thank you sir ! – Loegic May 27 '15 at 12:44
  • 13
    For some reason it took me three reads to finally see the :traitCollection part of that delegate method. I initially thought, "yes, I've implemented that" since the shorter version works for the other devices. Thanks! ... I've been beating my head against the wall as to why it wouldn't work for 6+. It's always the simplest things. – digitalHound Dec 04 '15 at 18:03
  • 2
    Why did Apple do this specific change for the 6/7 Plus in landscape? Why not just display a popover if that's what you requested? – bartzy Jan 19 '17 at 12:16
  • Thank you for this! Should I keep the shorter version of this (without the traitColleciton) also implemented if my minimum iOS is 9, or I'm good with just this method? – Lucas P. Mar 26 '18 at 17:12
6

In Swift 3, if you implemented the original adaptivePresentationStyle method, simply adding this code works:

func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
    return adaptivePresentationStyle(for: controller)
}
JKaz
  • 765
  • 6
  • 18
2

A note to people having issues with this:

This

- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *) controller traitCollection:(UITraitCollection *)traitCollection {
    return UIModalPresentationNone;
}

Is not the same as this

- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController: (UIPresentationController * ) controller {
    return UIModalPresentationNone;
}

The later will not get called / work the same as the former.

visc
  • 4,794
  • 6
  • 32
  • 58
1

Apple designed the iPhone 6 Plus presentation to behave that way, based on its size class.

To prevent the modal presentation on the iPhone 6 Plus, you'll have to override the trait collection (horizontal size).

You should be able to set the overrideTraitCollection property for the presentation controller:

presentedVC.presentationController.overrideTraitCollection = [UITraitCollection traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassCompact];

(Sorry for the Objective C! I haven't learned Swift yet.)

  • I'm sorry but it didn't work for me, I'm not able to override the traitCollection, the "mean to be" popover is still presented as page sheet on iPhone 6 plus landscaped only – Loegic May 26 '15 at 13:19
  • While intrigued, I don't have the time this morning to investigate this. I can offer a bounty on the question to draw some attention to it. :) –  May 26 '15 at 13:32
  • I saw it, thank you :) The traitCollection override seemed to be a great idea, but it seems to be ignored. – Loegic May 26 '15 at 13:34
  • well, it overrides the trait collection when you add this line before you set the modalPresentationStyle = UIModalPresentationPopover but, i think the UIPopoverPresentationController don't know about this change and still showing without the navbar to save/close the popover – Jorge Balleza Jul 03 '15 at 18:27