Reputation: 777
Before presenting a view controller I set the modalPresentationStyle
property to UIModalPresentationPopover
. This will present the view controller as a popover when running on devices with a regular horizontal size class (iPad and iPhone 6+ in landscape) and as modal/fullscreen on other devices. It's also possible to override this behaviour by overriding adaptivePresentationStyleForPresentationController
so that the view controller is presented as a popover on all devices.
I wonder if it's possible, after a view controller is presented, to know if it's presented as a popover or not? Just looking at the size class won't do it as it's possible that the view controller overrides adaptivePresentationStyleForPresentationController
.
The obvious answer would be that I, as the programmer, should know if I override adaptivePresentationStyleForPresentationController
or not but I want to write a function that can determine this in runtime for any view controller by passing in the view controller or maybe the UIPopoverPresentationController
(or any other object needed) as an argument.
Here's some code to present the view controller:
navigationController = (UINavigationController *)[MVSStore sharedInstance].addViewController;
navigationController.modalPresentationStyle = UIModalPresentationPopover;
[self presentViewController:navigationController animated:YES completion:^{}];
UIPopoverPresentationController *popoverController = navigationController.popoverPresentationController;
popoverController.sourceView = self.view;
popoverController.sourceRect = CGRectMake(20, 20, 20, 20); // Just a dummy
popoverController.permittedArrowDirections = UIPopoverArrowDirectionAny;
Here's the current code to detect if the view controller is presented as a popover or not. But as mentioned above it just looks at the size class which doesn't work for all cases.
+ (BOOL)willPresentTruePopover:(id<UITraitEnvironment>)vc {
return ([vc traitCollection].horizontalSizeClass == UIUserInterfaceSizeClassRegular);
}
I cannot find any property or function in UIViewController
or UIPopoverPresentationController
(or anywhere else) that gives me this information right away but maybe I'm missing something?
Upvotes: 6
Views: 2391
Reputation: 51
I'm attacking it in the same way you were, in that I set up the Done button with its target-action in Interface Builder. In order to remove it, I was testing if the popoverPresentationController != nil. On my testing device (iPhone 5 running iOS 10), this test successfully ignored the iPhone while executing on an iPad Pro running iOS 11. I ran into problems while testing it on an iPhone 8 running iOS 11. It appears in iOS 11 that a popoverPresentationController is now instantiated even when presenting the view modally. As a result, I am just testing the horizontal size class of the presenting view controller. Not sure if that's the correct way, but it works for me, since I can't find any way for the popoverPresentationController to tell me it is actually presenting modally.
weak var ppcDelegate: UIPopoverPresentationControllerDelegate?
...
if popoverPresentationController != nil &&
popoverPresentationController!.presentingViewController.traitCollection.horizontalSizeClass == .regular {
navigationItem.rightBarButtonItem = nil
popoverPresentationController?.delegate = ppcDelegate
}
Upvotes: 2
Reputation: 30573
You said you were trying to do this to remove the cancel/done button. Instead, only add the button in the case when it is needed.
The official way to implement this is first remove the Done button from your view controller and second, when adapting to compact embed your view controller in a navigation controller, now add the done button as a navigation item:
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.FullScreen
}
func presentationController(controller: UIPresentationController, viewControllerForAdaptivePresentationStyle style: UIModalPresentationStyle) -> UIViewController? {
let navigationController = UINavigationController(rootViewController: controller.presentedViewController)
let btnDone = UIBarButtonItem(title: "Done", style: .Done, target: self, action: "dismiss")
navigationController.topViewController.navigationItem.rightBarButtonItem = btnDone
return navigationController
}
func dismiss() {
self.dismissViewControllerAnimated(true, completion: nil)
}
Upvotes: 3
Reputation: 1547
Use the UIAdaptivePresentationControllerDelegate
method presentationController:willPresentWithAdaptiveStyle:transitionCoordinator:
. To query the presentation style at other times, ask the presentation controller for its adaptivePresentationStyleForTraitCollection:
, passing the current traits. These methods were added in iOS 8.3, and are not documented yet.
Upvotes: 2