如何知道视图控制器将作为弹出窗口或模态窗口呈现?

6
在展示一个视图控制器之前,我会将modalPresentationStyle属性设置为UIModalPresentationPopover。这将在具有常规水平尺寸类(iPad和横向iPhone 6+)的设备上以气泡窗口的形式呈现视图控制器,在其他设备上则以模态/全屏的形式呈现。还可以通过重写adaptivePresentationStyleForPresentationController来覆盖此行为,以便在所有设备上将视图控制器呈现为气泡窗口。
我想知道,在呈现视图控制器后,是否可能知道它是作为气泡窗口呈现的还是其他方式呈现的?仅查看大小类不足以做到这一点,因为视图控制器可能会覆盖adaptivePresentationStyleForPresentationController
显然,作为程序员的我应该知道是否覆盖了adaptivePresentationStyleForPresentationController,但我想编写一个函数,在运行时通过传入视图控制器或者UIPopoverPresentationController(或任何其他需要的对象)作为参数来确定任何视图控制器的情况。
以下是一些用于呈现视图控制器的代码:
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;

以下是用于检测视图控制器是否以弹出窗口的形式显示的当前代码。但正如上面提到的,它只查看大小类别,这对所有情况都不起作用。

+ (BOOL)willPresentTruePopover:(id<UITraitEnvironment>)vc {
    return ([vc traitCollection].horizontalSizeClass == UIUserInterfaceSizeClassRegular);
}

我找不到UIViewControllerUIPopoverPresentationController(或其他任何地方)中可以立即给我这些信息的属性或函数,但是也许我漏掉了什么?


只是好奇,你为什么想知道那个? - Khanh Nguyen
我会使用它来显示或隐藏取消按钮。在弹出窗口的情况下,我不需要显示取消按钮,因为通过在其外部点击可以关闭视图控制器。另一个原因是在视图控制器被关闭时更新父视图控制器。这目前是在父视图控制器的viewWillAppear和viewDidAppear中完成的。然而,当子视图控制器作为弹出窗口呈现时,viewDidAppear和viewWillAppear不会被调用(但是当模态时会被调用),因此我需要以某种特殊方式处理这种情况。 - Markus
@Markus,我添加了一个答案,展示了如何仅在需要时添加取消按钮。 - malhal
请查看此帖子:https://dev59.com/9V8d5IYBdhLWcg3wkSwV#37180653 - Slyv
3个回答

3
你说你想尝试这样做是为了移除取消/完成按钮。相反,只需要在需要时添加按钮。
官方实现方法是首先从视图控制器中删除完成按钮,然后,在适应紧凑模式时将视图控制器嵌入导航控制器中,现在将完成按钮作为导航项添加:
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)
}

完整教程

Screenshots


2
使用UIAdaptivePresentationControllerDelegate方法presentationController:willPresentWithAdaptiveStyle:transitionCoordinator:。要在其他时间查询演示样式,请向演示控制器询问其adaptivePresentationStyleForTraitCollection:,传递当前的特征。这些方法添加于iOS 8.3中,但尚未文档化

我没有成功地设置代理以使其工作。将视图控制器类设置为符合UIAdaptivePresentationControllerDelegate,然后使用popoverController.delegate = self;编译通过,但是我收到一个警告,self不符合UIPopoverPresentationControllerDelegate协议,且willPresent...函数没有被调用。如果vc符合UIPopoverPresentationControllerDelegate,则可以通过编译,但是该函数不会被调用,因为UIPopoverPresentationControllerDelegate接口没有暴露此函数(即使它本身符合UIAdaptivePresentationControllerDelegate)。 - Markus
好的,我设法让它工作了。它实际上正在正确地工作,但是我不太自信使用未记录的功能...我听说过有人因为这些问题而在AppStore审核时间上苦苦挣扎。我也更愿意找到一个从iOS 8.0开始就能工作的解决方案。 - Markus
哦,这些是未记录的,因为他们还没有来得及记录。这些方法存在于公共头文件中,并且对于App Store审核来说完全没有问题。 - Douglas Hill

2

我正在以与您相同的方式攻击它,即使用Interface Builder设置Done按钮及其目标操作。为了删除它,我正在测试popoverPresentationController != nil。在我的测试设备(运行iOS 10的iPhone 5)上,此测试成功地忽略了iPhone,而在运行iOS 11的iPad Pro上执行。当我在运行iOS 11的iPhone 8上进行测试时遇到了问题。似乎在iOS 11中,即使以模态方式呈现视图,也会实例化popoverPresentationController。因此,我只测试呈现视图控制器的水平大小类。不确定是否是正确的方法,但对我来说有效,因为我找不到任何一种方式可以让popoverPresentationController告诉我它实际上是以模态方式呈现的。

    weak var ppcDelegate: UIPopoverPresentationControllerDelegate?

...

    if popoverPresentationController != nil && 
        popoverPresentationController!.presentingViewController.traitCollection.horizontalSizeClass == .regular {

        navigationItem.rightBarButtonItem = nil
        popoverPresentationController?.delegate = ppcDelegate
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接