【问题标题】:iOS 13's presentationControllerDidDismiss() Not Called for Popover in Compact EnvironmentiOS 13 的 PresentationControllerDidDismiss() 在紧凑环境中未调用 Popover
【发布时间】:2020-03-27 16:02:30
【问题描述】:

我正在为 iOS 13 的新“卡片式”模式视图更新我的应用程序。使用UIAdaptivePresentationControllerDelegatepresentationControllerDidAttemptToDismiss()presentationControllerDidDismiss() 函数,一切运行良好。但是,对于将.modalPresentationStyle 设置为.popover 的视图,presentationControllerDidDismiss() 在紧凑型环境中呈现时不会被调用(例如手机或 iPad 处于拆分或滑过状态)。当在常规尺寸类环境(如 iPad 全屏)中呈现时,它会被正确调用。

我的代码设置非常简单:

显示弹出框的代码:

func showChooser() {
    // other setup code...
    navController.modalPresentationStyle = .popover
    navController.popoverPresentationController?.barButtonItem = self.viewController?.navigationItem.leftBarButtonItem
    self.present(navController, animated: true)
}

然后,呈现的控制器符合UIAdaptivePresentationControllerDelegate 并设置:

// This is in the presented view controller (i.e. the popover)
override func viewDidLoad() {
    // other setup removed for brevity…
    self.navigationController?.presentationController?.delegate = self
}

func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
    print("did dismiss")
    self.cancel?()
}

当视图在常规尺寸等级环境中呈现时,它会正确显示为弹出框。当用户在弹出框外点击时,会调用presentationControllerDidDismiss()。但是,相同的代码在紧凑的环境中呈现时,可以正确显示(作为卡片样式),但是当用户向下拖动视图时,不会调用presentationControllerDidDismiss()

如果我将 .modalPresentationStyle 更改为其他名称,例如 .pageSheet.formSheet,那么无论是在紧凑的演示文稿中还是在常规演示文稿中,它都可以正常工作。

我尝试在紧凑型环境中使用代理的 adaptivePresentationStyle() 将样式更改为 .formSheet,但仍然无法正确调用 presentationControllerDidDismiss()

更新: 我应该提到我目前的解决方法是检查大小类并根据需要更改.modalPresentationStyle

if self.traitCollection.horizontalSizeClass == .compact {
    navController.modalPresentationStyle = .automatic
} else {
    navController.modalPresentationStyle = .popover
    navController.popoverPresentationController?.barButtonItem = self.viewController?.navigationItem.leftBarButtonItem
}

这行得通,但似乎只使用.popover 样式应该正确适应并调用正确的委托方法。

更新 2: 我更新了上面的代码,以阐明 presented 视图控制器是处理委托方法的控制器。

另外,在深入研究之后,我注意到如果 presenting 视图控制器是委托并处理委托方法,那么这一切都按预期工作。由于它也适用于紧凑环境中所有.modalPresentationStyleexcept 弹出框的 presented 视图控制器,因此以这种方式显示弹出框时可能存在一些生命周期问题?

关于我可能做错了什么有什么想法吗?

【问题讨论】:

  • 很好的研究。一个问题。 willDismiss 怎么样?这叫什么?
  • @matt,不,也没有被调用。在紧凑环境中调用的唯一委托方法是adaptivePreesentationStyle()
  • 我会尝试重现此内容,如果我有任何想法,请告诉您。再次,良好的研究。同时还有一个想法:观察呈现的视图控制器确实不需要获取dismiss 委托方法,因为它自己的viewDidDisappear 会捕捉到这一点。
  • @matt,我很感激。关于viewDidDisappear 的好点。这在这种情况下可以工作。现在 iOS 默认使用这种卡片样式的模态视图,这在其他情况下也可以工作,因为在当前模态视图之上显示另一个模态时不再调用 viewDidDisappear
  • 好的,我已经给出了一些其他解决方法,这些解决方法将导致 willdid 按预期开始工作。很抱歉让您失望了,但我认为我们不能将此视为错误。

标签: ios swift uiviewcontroller uikit ios13


【解决方案1】:

如果您的 viewController 嵌套在另一个 navigationviewController 中

override func viewDidLoad() {
    super.viewDidLoad()
    presentationController?.delegate = self
}

【讨论】:

    【解决方案2】:

    非常感谢该示例 - 只是为了扩展来自 Matt 的详细信息,并且为了那些寻找通用示例(通过创建独立的 viewController)的人的利益,我相信类似下面的内容也应该有效:

    func presentExampleViewController() {
        // Any other setup code specific to the view in your app can go here...
        let exampleViewController = SomeCustomViewController()
        exampleViewController.presentationController?.delegate = exampleViewController
        self.present(exampleViewController, animated: true)
    }
    

    【讨论】:

      【解决方案3】:

      navController.presentationController?.delegate = // * navController.viewControllers[0] 放在self.present(navController, animated: true) 之后,否则您的presentationController 可能为零

      【讨论】:

        【解决方案4】:

        问题只是时间问题之一。您在第二个视图控制器中执行此操作:

        override func viewDidLoad() {
            self.navigationController?.presentationController?.delegate = self
        }
        

        太晚了。您可以在您配置和执行演示的位置设置委托:

        func showChooser() {
            navController.modalPresentationStyle = .popover
            navController.popoverPresentationController?.barButtonItem = 
                self.viewController?.navigationItem.leftBarButtonItem
            navController.presentationController?.delegate = // *
                navController.viewControllers[0] 
                as! UIAdaptivePresentationControllerDelegate
            self.present(navController, animated: true)
        }
        

        如果您更愿意坚持让第二个视图控制器将自己设置为委托,请早点进行。第一个好机会是willMove

        override func willMove(toParent parent: UIViewController?) {
            self.parent?.presentationController?.delegate = self
        }
        

        【讨论】:

        • 谢谢你,@matt。这很有帮助。在我呈现弹出框之前设置委托非常有效。我曾希望让第二个视图控制器来做这件事,但我会根据这个调整代码。我一定很幸运,时间适用于其他模态样式。另外,由于某种原因,我的模态视图中从未调用过willMove,但didMove 是。在didMove 中设置代理不起作用,我认为此时也为时已晚。感谢您的帮助。
        • 调用willMove失败说明你的其他代码有错误,比如在某些覆盖中没有调用super
        • 顺便说一句,它不仅仅是模态样式,而是你被包裹在导航控制器中的事实。因此,当您获得 viewDidLoad 时,演示正在进行中。
        • 回复:willMove 我想我会确保在需要的地方调用了super,但我会再次检查。关于导航控制器中演示时间的好点。很有帮助的讨论。
        猜你喜欢
        • 2015-12-15
        • 2012-07-23
        • 2020-11-01
        • 1970-01-01
        • 2019-12-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多