Setting UIModalPresentationStyle for iPhone 6 Plus in landscape? - ios

I want to always present a view controller in a popover on all devices and all orientations. I tried to accomplish this by adopting the UIPopoverPresentationControllerDelegate and setting the sourceView and sourceRect. The segue in the storyboard is configured as a Present As Popover segue. 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
}

Implement the new (as of iOS 8.3) 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.

Related

Modal UIViewController with presentation style formSheet is not displayed correctly on iPhone XS Max and iPhone XR

I have a view controller presented from a segue modally. Its presentation style is set to Form Sheet.
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
return .formSheet
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
segue.destination.presentationController?.delegate = self
}
On iPhone X and iPhone 8 Plus it works as expected, on iPhone Xs Max and Xr the width of the controller is respected, but the height is wieredly stretched. I have no way of confirming if this is simulator bug, iOS bug or expected behaviour as I don't have Xs Max myself.
Better use the modal presentation style overFullScreen for compact horizontal size clases and leave the formSheet for the horizontally regular ones.
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
if controller.traitCollection.horizontalSizeClass == .regular {
return .formSheet
}
return .overFullScreen
}

Popover covers entire screen iOS

I am trying to implement a popover whose anchor is a bar button item for my iphone app. I have connected the bar button item to the view controller via a segue pathway configured as show as "present as popover." I have also set my own size for the view controller and selected "use preferred explicit size." Based on previous posts about this similar topic, I have implemented the following code for my popover. However, the popover is still covering the entire screen, probably because my adaptivePresentationStyle method is not being called ("hello" does not print to the screen). Note that I have also implemented the UIPopoverPresentationControllerDelegate. Where did I go wrong?
override func prepare (for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "popoverLogin" {
let popoverViewController = segue.destination
popoverViewController.modalPresentationStyle = UIModalPresentationStyle.popover
popoverViewController.popoverPresentationController!.delegate = self }
}
// MARK: - UIPopoverPresentationControllerDelegate method
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
// Force popover style
print ("hello")
return UIModalPresentationStyle.none
}
Thanks!
In my case your code works and popover is presented normally!
Make sure your segue has the right "Kind": "Present As Popover".

Perform Function when Popover is Dismissed

I have a popover that is using the same view controller that calls it.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "groupSelect" {
let popVC = segue.destination
popVC.popoverPresentationController?.delegate = self
}
}
func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.none
}
However, because I used the storyboard to make everything, I'm not really sure how or where I can take over or add code when the popover gets dismissed. In Xcode 8.2 with Swift 3, adding a popover with the storyboard editor automatically makes the popover dismiss when the user touches outside the popover. Everything is working great, the only problem is that when I return from the popover, the table under it won't have the reload function called so any changes made in the popover don't take effect for the user.
Implement UIPopoverPresentationControllerDelegate method popoverPresentationControllerDidDismissPopover which tells the delegate that the popover was dismissed.

How do I make popover views not ignore the device's size class?

I have a storyboard that I have made using Interface Builder. I have modified it for the "Regular Width | Regular Height" size class. When displayed normally (taking up the entire screen), the size class modifications are acknowledged, and it does look different on the appropriate devices.
However, when displayed as a popover view (the segue used to present it is of type "Present as Popover"), the size class modifications are ignored. No matter the device, the popover view is displayed using the default "Any" size class.
I'm looking for a way to force the size class of the device to be acknowledged, and display the storyboard with the appropriate changes. I'm not using the default popover view size; the size is different on every device.
One last thing to note is that I have overridden a function and added a new one to the view that displays the popover view, in order to ensure that the popover view is displayed as a popover on an iPhone, as opposed to a full view:
//Forces the settings view controller to be displayed as a popover on an iPhone
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.destinationViewController as? SettingsViewController != nil {
if let controller = segue.destinationViewController as UIViewController! {
controller.popoverPresentationController!.delegate = self
controller.preferredContentSize = CGSize(width: view.frame.size.width/2, height: view.frame.size.height/3)
}
}
}
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
// Return no adaptive presentation style, use default presentation behaviour
return .None
}

UIModalPresentationPopover for iPhone 6 Plus in landscape doesn't display popover

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
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.
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)
}
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.)
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.

Resources